[BUG][FIX] WeakKeyDictionary>>keysAndValuesDo:

Richard A. O'Keefe ok at cs.otago.ac.nz
Mon Jun 21 04:52:36 UTC 2004

Martin Wirblat <sql.mawi at t-link.de> continues:
	Your argumentation in this whole thread was centered around the idea 
	that there is the premise that the equality of #= is about state and 
	nothing else.

I don't know where you get the "nothing else" from.

However, yes, the evidence is there.
Since my last message in this thread, my copy of "Smalltalk-80, The
Language and its Implementation" has been restored to me, so I'll
quote page 96:

    The important comparisons specified in class Object are
    equivalence and equality testing.  Equivalence (==) is the test of
    whether two objects are the same object.  Equality (=) is the test of
    whether two objects represent the same component.  The decision as to
    what it means to be [sic.] "represent the same component" is made by the
    receiver of the message; each new kind of object that adds new instance
    variables typically must reimplement the = message in order to specify
    what of its instance vairables should enter into the test of equality.
    For example, equality of two arrays is determined by checking the size
    of the arrays and then the equality of each of the elements of the arrays;
    equality of two numbers is determined by testing whether the two
    numbers represent the same value; and equality of two bank accounts
    might rest solely on the equality of each account identification number.

We draw the following principles from this:
(1) == is for testing IDENTITY, = is for testing what the STATE represents.
(2) "each new kind of object ... typically must reimplement the = message"
(3) = need not example all the instance variables, only enough to serve
    the purpose.  As a specific example, (page 136) "We can use the
    equivalence test (==) rather than equality since objects representing
    Characters are unique", so objects with unique states can correctly
    use the #== implementation of #=.

	You concluded that the question of changing Sets in a 
	Set is by definition sort of nonsense. Furthermore you argued that 
	every "competent" programmer has to know this. 

I quoted the Java documentation to the effect that changing *ANYTHING*
in a Set or other equality-based data structure is a drastically bad idea.
Smalltalk is no different from Java in this respect.  And yes, any
competent programmer damn well MUST know when it is safe to mutate objects
and when it isn't.
	My code snippet had only one intention. It wanted to show that this
	premise, while being valid for you (it may be even sound), seems to be
	not universally accepted or applied.

Yes, but that code snippet COMPLETELY FAILED at that.

	For that it needed to find only a _few_ classes which are
	contradicting the premise.  Well, it found _many_.

No it didn't.  To refute me, you need to exhibit classes which
(a) *don't* redefine #= and
(b) *should* redefine it according to me and
(c) *nevertheless* represent good coding.

Your code snippet satisfied (a).  There is no dispute about that.

Your code snippet did NOT satisfy (b) at all.  I doubt whether any code
snippet could.  It requires the hard work of human analysis.  You did not
even BEGIN that hard work.  I did, and I found that many of the classes
that use the default implementation (==) of #= are, by my criteria, RIGHT
to do so.  I specifically pointed to nearly 400 Morphic classes and a
large number of MVD and Stream classes as classes reported by your code
snippet (under (a)) which do NOT fit test (b).

Let me emphasise this, since the point didn't seem to sink in the first time:
according to the principle "#== compares identity, #= compares state" a
quick check showed that at least 500 of the classes your snippet are *RIGHT*
to not reimplement #=, and so are wildly irrelevant to any attempted
refutation of me.

Just now I did
    Smalltalk allClasses atRandom
and the answer was B3DSceneExplorerMorph.  That's one of the hundreds of
classes which *rightly* doesn't redefine #= .  I tried again, and got
ShadowDrawingCanvas.  This too doesn't redefine #=.  It turns out that
canvases often point to unshared objects with unique state, so the
default implementation is (usually) right.  (Does it really make sense to
have two canvases pointing to the same Postscript stream, for example?)

Now, it turned out that some of the classes your snippet reports *do*
satisfy point (b).  It wasn't you did the work of analysis to discover
this, but me.  And what I found when I examined them was that point (c)
fails:  those classes do not represent good coding.

	Not the precise number, but I took it for granted that you would
	see the principle behind it.  In this context the snippet is the
	opposite of "deeply flawed", it shows exactly, what I wanted to show:
	That the question is not simply nonsense or immediately answered
	by the mere existence of this premise.

No, the snippet really IS deeply flawed, because it DOESN'T show that at all.

What you have to show is that there are classes which on my principles
should reimplement #= but don't, and nevertheless represent good Smalltalk
code.  Your snippet doesn't do that.  It is *obviously* wrong to the tune
of several *hundreds* of classes.

Now let's dispose of a rather offensive phrase: "valid for you".
Statements may be true OF one person but not another,
but they are VALID for everyone, or not at all.

Like I said, "if an object is in an equality-based collection, don't do
anything to it that could change its equality or hash" is valid for
*every* Java programmer; it's official.  It's also *valid* for Smalltalk
programmers, whether they know it or not, whether they like it or not.

It's just like that other famous rule "don't change a collection while
you are iterating over it" which Java (since 1.2) actually goes to the
trouble of checking and enforcing at run time.  This is not a rule that
AWK programmers have to worry about, when you do 'for (key in array)'
AWK makes a virtual copy of the keys of the array and iterates over the
virtual copy.  It's a *contingent* fact about library design:  the
collection methods do not make (virtual) copies of the collections they
iterate over (although in principle they could have).

In the same way, it's a *contingent* about library design that putting
an object in a Set doesn't make a (virtual) copy of that object; but since
the Smalltalk library *was* designed that way, we have to live with the

I am still waiting for an example where there is a set whose elements
include Sets and things that are not sets, where the non-set elements
should be compared using #= (NOT #==) but the Sets should be compared
as if using #==.

More information about the Squeak-dev mailing list