nothingmuch has asked for the wisdom of the Perl Monks concerning the following question:
This question is really about perl internals, with a bit of an exposition so that you guys can say "no stupid, there's a much more obvious solution".
I'm implementing Tie::RefHash::Weak (don't click the link, it's not there yet). It's pretty simple. Just weakens the value of $s->[0]{$k}[0], which is the key-that-is-a-reference, and also makes $s->[0]{$k}[1] store a weak reference to the value, instead of the value itself, so that we don't interfere with the destruction of stored values. This way, when other copies of the reference used as a key are gone, the weak copies of the references are set to undef. The reference to the value is also weak, because we pretend the whole key-value-pair is weak. It's arguable whether that's the "correct" behavior.
This is simple to do: you just modify all the accessors so that they also check for undefness of the copy of the reference, and pretend it's not there when it became undefined.
This has a problem though. If we fill the hash with references, and slowly objects start going away, then we get a hash filled with duds.
There are three ways to deal with this. The first is to ignore the problem. We clean up lazily inside NEXTKEY, and all is well. Sort of. No big O complexity is added to the hash operations, but a constant overhead, though negligable is added to NEXTKEY. However, between iterating the hash with each, or calling keys or values on it, the hash is filled with dead bloat.
The second way is to iterate the whole hash and purge it before every operation. This ensures that none of this leaking will occur, but is very expensive as the hash grows, because in effect the hash operations become O(N) + whatever they were before. Even worse, something like values is in theory much slower, because it calls NEXTKEY and FETCH, so it's O(N*(2N)) instead of O(N). NEXTKEY could be kept lazy like before, I guess. Either way, a hash with more than several hundred values will start becoming a computational bottleneck, for the sake of conserving several undefs and references to the undefs. This is definately not worth it.
The third way is hypothetical, at least with the knowlege I have. Perl sets the references to undef. It does this with the magic_killbackrefs function, somehow. The problem is that I know nothing of perl internals, and now is not a good time to learn.
In short, can magic_killbackrefs be used somehow, to that I can call the tie's DELETE method when the undefs are written to the weak references?
There is a f fourth, bonus solution. We bless whatever the reference points to, and use DESTROY. But this ruins the data the user stores in the RefHash. OTOH, since we have a reference to the value that will be destroyed, perhaps it's destruction can be hooked instead of the backref killing, without making it into an object, or changing it's DESTROY method.
Anyway, what do you think? I'm happy with the leak, because the hashes should be regularly (but not oftenly) iterated, and the data set is small.
If I want to release this to the CPAN though, I think it's half baked at the very best.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Catching the death of a weak reference
by ysth (Canon) on Oct 28, 2004 at 14:49 UTC | |
|
Re: Catching the death of a weak reference
by perrin (Chancellor) on Oct 28, 2004 at 15:48 UTC | |
by nothingmuch (Priest) on Oct 28, 2004 at 16:11 UTC | |
by tilly (Archbishop) on Oct 28, 2004 at 16:42 UTC | |
by perrin (Chancellor) on Oct 28, 2004 at 16:38 UTC | |
|
Re: Catching the death of a weak reference
by bibliophile (Prior) on Oct 28, 2004 at 14:00 UTC | |
by nothingmuch (Priest) on Oct 28, 2004 at 14:16 UTC | |
|
Re: Catching the death of a weak reference
by Anonymous Monk on Oct 29, 2004 at 19:24 UTC | |
|
Re: Catching the death of a weak reference
by nothingmuch (Priest) on Dec 17, 2004 at 10:46 UTC |