Changes Set>>do: from
do: aBlock tally = 0 ifTrue: [^ self]. 1 to: array size do: [:index | | each | (each _ array at: index) ifNotNil: [aBlock value: each]]
to
do: aBlock tally = 0 ifTrue: [^ self]. array do: [:each | each ifNotNil: [aBlock value: each]].
The difference is that adding to a Set or Dictionary can put a new rehashed hashed hash table into "array"
In the original version, if any block inside of a "do:" or any of the many loops that depend on "do:" called code that added to that Set then there was a chance the set would grow and rehash - and some element would be visited more than once and some not at all.
The way it is with this change, adding to a Set in a loop adds an element that might not be visited, and deleting an element doesn't necessarily mean the element won't be visited but the meltdown scenario can't happen.
And of course the new version is at least as fast as the old one.
One other topic. The fact that Sets (and the many classes derived from Set) never shrink is a potential memory leak.
There's probably not any apps that leak this way - after all the fastest way to clear a Set or Dictionary is "aSet_Set new" not "aSet do: [:e| aSet remove: e ifAbsent: [] ]"
While this leak may not be important in general memory leaks are probably imporant because many people work by saving an image every day and that's the equivalent to running Squeak forever.
Joshua Scholar
squeak-dev@lists.squeakfoundation.org