|Pathologically Eclectic Rubbish Lister|
Quickly detecting variable writesby sfink (Deacon)
|on Jan 05, 2007 at 01:58 UTC||Need Help??|
sfink has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to make a nicer API for a work application without slowing it down much at all. For this, it would be really convenient if I could detect whether a variable has been modified. For example, consider the following code:
Now say that @kabluther is almost always empty, but when it's not, it has a bazillion entries. (Similarly, I could have used an 'if' statement where $x is modified in only one branch.) Is there any tricky way to detect whether $x was modified, preferably without slowing things down much at all? (Or maybe it only slows down that first modification, but then runs at full speed for the remaining.)
In my application, if $x is updated, then I need to notify watchers, and that may trigger all kinds of cascading computation. So I'd like to only do that notification when it's actually needed, without adding a burden to the programmer to explicitly inform the system.
It's fine if it isn't 100% correct -- it's ok to occasionally claim that $x has been modified when it actually hasn't. It is not fine to claim that $x has not been modified when it actually has.
The mechanism shouldn't require the code to be written any differently, although I can automatically insert code before or after the call to the function.
One option would be to tie $x to something that overloads STORE to mark $x as modified, then unties $x. But (assuming it's even possible) I don't want to slow down reads of $x either.
What I was originally thinking of when I asked this question was, for a numeric variable, upgrading it to a string if necessary and then turning off SvNOK. When the variable is modified, it would need to convert the string to a float and turn SvNOK back on. Which is a dumb idea, because it would do the same thing on a read.
It's fine to use XS. Is there separate get and set magic, so that I could do what I wanted with the tie? As in: don't have any get magic, and have the set magic record the variable in a separate table and then clear the magic.
I don't actually know how speed-critical this is -- not even enough to know whether it would be better to always assume the variable was updated, or tie'ing the variable to something that records the update (and doesn't untie it). This is infrastructure that a bunch of other people will use, so I can't just benchmark one use of it and decide from that. The cost of incorrectly assuming that the variable has been updated varies from practically zero to infinite, but is usually small.
I'm hoping someone else has a simple but effective idea that is cheap enough that it will barely slow down the common case while significantly speeding up the occasional case when incorrectly assuming the variable changed is very expensive.