Ah Ah, I found the guilty: Set>> do: use 1 to: array size do: [:i | (array at: i) ... But array inst. var can be overwritten inside the loop due to #rehash OK, OK, I thought I would catch it be redefining do: in WeakKeyDictionary do: aBlock "This needs to be redefined because array inst. var. can eventually be overwritten during the loop (due to rehash, due to fullCheck) and make super fail." tally = 0 ifTrue: [^ self]. array do: [:each | each ifNotNil: [aBlock value: each]] But ARGHH SUPER EVIL, this method does not get executed BECAUSE : Dictionary>>associationsDo: aBlock "Evaluate aBlock for each of the receiver's elements (key/value associations)." super do: aBlock ARGHH, it really uses super do:, not my brand new #do: This is a good reason I DON'T LIKE INVOKING super WITH A DIFFERENT selector... Does not matter, I will just redefine Set>>do:, but that was my evil minute of the day... Nicolas 2010/1/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Oh, now it fails due to WeakIdentityKeyDictionary bug...
Nicolas
2010/1/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
I wrote this test pre-closure. The problem with closures is that they are optimized to retain a pointer to the values of outer temporary variable they use when activated. Thus the BlockClosures forAnyTwoEqualObjects ofDifferentIdentity registeringAnActionAtFinalizationForEachObject all refer to 'hello' pointed by o1 and its copy pointed by o2. In other words, o1 and o2 are not the single pointers to the String 'hello' and its copy. thenForcingFinalizationOfObjects only clean o1 and o2, but omit to clean the closures that still point to 'hello'... Thus, 'hello' is not finalized. One possibility is to also clean the closures pointing to 'hello'. But now the code is tricky... It's aim was to be simple damned :)
Nicolas
here is a corrected version :
testFinalizationOfEquals     "self debug: #testFinalizationOfEquals"
    | finalizationProbe o1 o2     forAnyTwoEqualObjects     ofDifferentIdentity     registeringAnActionAtFinalizationForEachObject     thenForcingFinalizationOfObjects     implyBothRegisteredActionsAreExecuted |
    finalizationProbe := Set new.     o1 := 'hello' copy.     o2 := 'hello' copy.     forAnyTwoEqualObjects := [o1 = o2].     ofDifferentIdentity := [o1 ~~ o2].     registeringAnActionAtFinalizationForEachObject := [         o1 toFinalizeSend: #add: to: finalizationProbe  with: 'first object finalized'.         o2 toFinalizeSend: #add: to: finalizationProbe  with: 'second object finalized'].     thenForcingFinalizationOfObjects := [         forAnyTwoEqualObjects := ofDifferentIdentity := registeringAnActionAtFinalizationForEachObject := nil.         o1 := o2 := nil. Smalltalk garbageCollect].     implyBothRegisteredActionsAreExecuted := [finalizationProbe size = 2].
    self         assert: forAnyTwoEqualObjects;         assert: ofDifferentIdentity;         should: [             registeringAnActionAtFinalizationForEachObject value.             thenForcingFinalizationOfObjects value.             implyBothRegisteredActionsAreExecuted value].