Last night while at dinner, Georg Heeg shared an interesting scenario they ran into using ephemeron finalizations. First of all, let's create an association:
association := 'The Key' -> 'The Value'.
Now store the association in a weak object and attach some finalization action to it (in this case, I'm using the withLastRites: API provided by the Weaklings package).
weakAssociation := association withLastRites: [:value |
Transcript show: 'Resurrecting Association'; cr.
association := value].
Also, store the value of the association weakly.
weakValue := association value withLastRites: [:value | Transcript show: 'Finalized: ' , value; cr].
So if we evaluate all of that, we can inspect the three variables and make sure they each hold the right thing.
Now what happens when we set assocation to something else?
association := 'Another Key' -> 'Another Value'.
If we're quick, we can check to make sure association is now the new one.
Eventually (or sooner if we force a garbage collect), our finalization blocks will run. And we'll find that the value of association has reverted to the original value. This may not seem like a problem until you imagine a scenario where we are interfacing with a reference counting collector. In such a case, we might be using the finalization blocks to decrement a the reference count. For some reason, we've decided to counter the parent object's decrement. But the child object gets decremented still. I'm not sure what the solution would be. I think I'm convinced that the finalizer is behaving correctly.
Possibly one solution would be to use a two phase finalization if you know you're doing something like this. The first level finalizers actually create a secondary weakling with last rites that actually do the decrementing. I'm not sure this would work, I'll go ponder the diagrams so more here in a minute.
One thing I discovered looking at this is a possible shortcoming in MournfulWeakling. In the example above, even though we "resurrect" the association back into a normal variable, the weakling's value will be nil after the finalization has run. I might want to reset the value of the weakling so that it remains. The problem is that the current flow of code is such that the finalization runs BEFORE we nil the value. So if the finalization block were to set the value, it would be promptly nil'ed after the block. It seems upon reflection that this perhaps ought to be reversed. Thoughts?