The standard does *not* support - a removeAll: a - [was: Re: [BUG] Collection>>removeAll:]
jwelton at pacific.mps.ohio-state.edu
Tue Sep 10 13:54:40 UTC 2002
Richard A. O'Keefe wrote:
> "Lex Spoon" <lex at cc.gatech.edu> wrote:
> > For example, suppose you looked at the
> > following code, which worked:
> > a removeAll: a
> > and then changed it to this, which doesn't work:
> > a do: [ :each | a remove: each ]
> I replied about the first fragment:
> > Right. Here is a call to an operation *inside* an encapsulation
> > boundary which can do whatever it wants.
> and about the second:
> > I thought it was generally agreed in this and related discussions
> > that good programmers _ought_ to know that it is a bad idea to modify
> > a container while it is running an iterator method.
> Note, that the programmer might not know that the two a's are the same:
> a do: [ :each | b remove: each ]
> Yes, but now that is a different example, and there are very different
> things to say about it. Anyone who has attentively read "Smalltalk with
> Style", for example, knows that if you do this it is YOUR responsibility
> to ensure that 'a' and 'b' are NOT the same.
> An error mesage lets the programmer know as soon as possible that a and
> b are sometimes the same.
> If you can arrange for Squeak or any other Smalltalk to report an
> error for
> a do: [:each | b remove: each]
> when b == a, more power to you. That could be an excellent thing.
Richard, I think you misunderstand Lex's point. I believe it is that
a reasonable programmer might rewrite a working call
a removeAll: b
b do: [:each | a remove: each].
Now, if #removeAll: detects the special case a==b and handles it, it
is possible that this case happens in practice, and the programmer's
rewritten code will break silently. On the other hand, is #removeAll:
detects a==b and throws an error, this case probably does not happen
in practice, and the programmer's code will work. Therefore, given
that this is a reasonable transformation for the programmer to make,
throwing an error is safer.
I don't buy it, though. I don't believe that it is, in general, a
reasonable transformation to make. It is longer and less intention
revealing. It is more error-prone than either fixed version of
#removeAll:, since it has the same silent failure everyone seems to
agree should be fixed in the current implementation of #removeAll:.
It is also potentially slower, since it cannot benefit from (future)
enhancements to #removeAll: performance.
In any case, the moment you write the explicit loop, the special case
becomes your responsibility, either way you think it should be
More information about the Squeak-dev