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

Richard A. O'Keefe ok at cs.otago.ac.nz
Thu Sep 5 05:37:30 UTC 2002


"Lex Spoon" <lex at cc.gatech.edu> wrote:
	This kind of silent fix can lead to trouble later when you make things
	slightly more complicated.

But that's not what he gives an example of.

	For example, suppose you looked at the
	following code, which worked:
	
		a removeAll: a
	
Right.  Here is a call to an operation *inside* an encapsulation
boundary which can do whatever it wants.

	and then changed it to this, which doesn't work:
	
		a do: [ :each | a remove: each ]
	
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.

This is precisely the kind of explicit user-written iteration which
all parties have hitherto agreed is _obviously_ unlikely to work.
	
	It seems better to make it an error.

This argument has the form
    "Because a working method call can be replaced by code
     that is obviously unlikely to work,
     therefore the working method should be made to signal an error."

I don't see any logic in that.  To start with, just how likely is it that
someone would replace a call to a method in someone else's class with code
that, even if it worked, might take O(N**2) time or worse?  Heck, someone
could turn
    x := y*z
into
    x := 0. [z = 0] whileFalse: [x := x+y. z := z-1]
and if y or z was a floating-point number, the result could be grossly
inaccurate.  Is that an argument for making * signal an error when given
floating-point numbers, or returning equally inaccurate results?

In general, suppose there is some possibly fairly simple piece of code
such that we as human beings can figure out what the author probably
_meant_ to do, but it doesn't work.  Call that code B for broken.
So we construct a new method which recognises the particular situation
and produces a meaningful answer according to a clean semantics.  Call
that code C for correct.  Now, the whole _point_ of developing C is so
that C can replace B.

Lex Spoon's argument is that because someone could replace a call to C
with the original B, C should signal an error.  That is, you should NEVER
be able to replace broken code with working code.

I for one am unpersuaded.

	PS -- an alternative approach to this mess might be to mark a collection
	while it is being iterated, and for all modification commands to check
	whether the mark is turned on.
	
Which is close to the way Java does it, except that Java "Iterator"
objects come with a "remove()" method to remove the current item as well.
I already suggested this 'locking' technique, and have used it.




More information about the Squeak-dev mailing list