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:
sub onTick { our $x; # Initialize and associate $x with some external value foreach (@kabluther) { $x += $_->getSkookiness(); } return $x; }
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.


In reply to Quickly detecting variable writes by sfink

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.