The standard does *not* support - a removeAll: a - [was: Re: [BUG] Collection>>removeAll:]

Jesse Welton 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
as
    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
handled.

-Jesse



More information about the Squeak-dev mailing list