[Pharo-project] Fwd: [squeak-dev] Re: WeakRegistry>>remove: - when you'll be in trouble

Igor Stasenko siguctua at gmail.com
Sun Oct 10 21:32:37 EDT 2010

2010/10/11 Levente Uzonyi <leves at elte.hu>:
> On Mon, 11 Oct 2010, Igor Stasenko wrote:
>> 2010/10/11 Levente Uzonyi <leves at elte.hu>:
>> On Mon, 11 Oct 2010, Igor Stasenko wrote:
>>> On 10 October 2010 23:43, Levente Uzonyi <leves at elte.hu> wrote:
>>> On Sun, 10 Oct 2010, Igor Stasenko wrote:
>>>> A current implementation of this method
>>>> remove: oldObject ifAbsent: exceptionBlock
>>>>        "Remove oldObject as one of the receiver's elements."
>>>>        oldObject ifNil: [ ^nil ].
>>>>        ^(self protected: [ valueDictionary removeKey: oldObject
>>>> ifAbsent:
>>>> nil ])
>>>>                ifNil: [ exceptionBlock value ]
>>>> simply removes a previously registered object from registry and voila.
>>>> Now lets get back to our discussion about multiple finalizers per
>>>> object and using them in weak subscriptions etc.
>>>> Suppose i am added a socket to weak registry,
>>>> and suppose i am added a weak subscription to it.
>>>> Now, if i do 'socket close' , it tells weak registry to remove it from
>>>> list.
>>>> And what we'll have:
>>>> - socket handle is closed
>>>> - socket is wiped from weak registry
>>>> - but weak subscription still listed somewhere in a list of
>>>> subscriptions
>>>> My suggestion is, that upon #remove:,
>>>> a weak registry should notify all executors that object of interest
>>>> are no longer takes part in finalization scheme,
>>>> so they should not count on receiving #finalize eventually.
>>>> In other words:
>>>> remove: oldObject ifAbsent: exceptionBlock
>>>>        "Remove oldObject as one of the receiver's elements."
>>>>        oldObject ifNil: [ ^nil ].
>>>>        ^(self protected: [ | executor |
>>>>            executor := valueDictionary removeKey: oldObject ifAbsent:
>>>> nil.
>>>>            executor discardFinalization.
>>>>        ])
>>>>        ifNil: [ exceptionBlock value ]
>>> It's only an issue with the new WeakRegistry implementation, previous
>>> implementations don't have such problem. I think changing the method as
>>> you
>>> suggested, implementing WeakFinalizerItem >> #discardFinalization as
>>> "executor := nil" and changing WeakFinalizerItem >> #finalizaValues to
>>> ignore the executor if it's nil will fix the problem. Am I right?
>>> I don't get how "multiple finalizers per object" is related to this
>>> problem
>>> at all.
>> No, you miss the point.
>> When you removing object from weak registry, it is important , time to
>> time to tell all of its executors,
>> that they will no longer receive #finalize, because object is no
>> longer a member of weak registry.
>> If you simply set executor := nil, it does nothing, an executor itself
>> did not notified that he won't be needed
>> in any possible future.
>> So, if your finalization action is to remove some object(s) from the
>> list , you'll get your list dirty after object will die,
>> because #finalize will be never sent to your executor.
>> Here the simple test case:
>> | coll obj someWrapper |
>> coll := OrderedCollection new.
>> obj := Object new.
>> someWrapper := WeakArray with: obj.
>> coll add: someWrapper.
>> obj toFinalizeSend: #remove: to: coll with: someWrapper.
>> obj finalizationRegistry remove: obj.
>> obj := nil.
>> Smalltalk garbageCollect.
>> self assert: coll isEmpty
>> the point is, that once you doing a #remove: ,
>> your finalization scheme is broken.
>> I don't get you. When you remove an object from a WeakRegistry, you tell
>> the
>> system that you want the object removed and all related executors deleted.
>> So the executors should never receive #finalize, they should be thrown
>> away.
>> Even if there's action to be done with the executors (which is pointless
>> IMHO since those will be thrown away, but who knows), doing them is the
>> responsibility of the sender of #remove:.
> Let us get back to multiple finalizers per object,
> when you have two separate places, which adding possibly different
> executors for a single object
> without knowing about each other (otherwise why would you want to add
> two finalizers instead of one).
> Now if one decides to do #remove: ,
> how to ensure that second one won't be left with dirty/invalid state?
> It's not ensured, and it doesn't have to be. The sender of #remove: takes
> all responsibility. It can decide to add some executors back to the registry
> if that's necessary.
> If you want to keep your executors safe from some other code, which may
> #remove: your objects from a WeakRegistry, then you can create a private
> WeakRegistry and store your executors there, just like Sockets and
> FileStreams do.

Conclusion: weak registry don't have to support multiple finalizers
per single object.
Instead, if one sees the need to control a finalization of certain
object(s) in own way,
indepentently fron any other, then he should use a private weak
registry (like Sockets and FileStreams do),
and register object and its executor there.

Best regards,
Igor Stasenko AKA sig.

More information about the Pharo-dev mailing list