Sewi has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I need to track changes deep into a hash (or array) reference.

sub foo { my $self = shift; $self->{changed}->{foo} = shift if $#_ > -1; return $self->{changed}->{foo} || $self->{data}->{foo}; } $x->foo('bar'); # This is recognized push @{ $x->foo->{bar}->{itemlist} },1; # This isn't

(I shortened the return part of foo, the original one is also dealing with undef values correctly.)

If foo holds a hash ref, the structure below this is completely unpredictable. Converting everything into a deep object structure (= $x->foo->bar->itemlist) would take a lot of time.

(How) could the "parent" package $x get some kind of notification if any deep value is changed?

I'd like to avoid a deep comparison between $self->{data} and $self->{changed}

Thank you all

Replies are listed 'Best First'.
Re: Deep-bless a HASH
by kennethk (Abbot) on May 31, 2011 at 14:29 UTC
    If you want a quick and efficient listener on a value, the only way I know of doing this is that deep object structure that "would take a lot of time".

    The alternative is polling the data structure, which will generally be slow but speed may not be an issue for you. Rather than rolling your own, it looks like Data::Compare does roughly what you'd need (assuming I understand spec).

Re: Deep-bless a HASH
by Sewi (Friar) on May 31, 2011 at 14:17 UTC
    Thoughts for the problem which may help solving the issue:
  • Any ref which has to be tracked has to exist at object-creation-time
  • Any newly added ref will be added through a method - and will end up in {changed} anyway
  • I could walk down the tree at creation-time of the object and tie() all ref's to a helper package but this doesn't feel like a good solution. The same for creating a deep copy at creation time and deep-compare it to {data} just before the changes are flushed to storage.

Re: Deep-bless a HASH
by GrandFather (Saint) on May 31, 2011 at 21:43 UTC

    Maybe instead of thinking in terms of tracking data changes you ought think in terms of the actions that may change the data and generate some form of notification that the data has changed. Anything interested in the data structure registers interest (probably by providing a callback sub) and does whatever is appropriate when the notification is fired.

    True laziness is hard work
Re: Deep-bless a HASH
by bluescreen (Friar) on May 31, 2011 at 23:28 UTC

    I may divert a little bit here, but usually when your objects have to deal with more than one or two levels of depth that indicates me that code smells. Your system would either hard to change or fragile.

    What I'd do is first ask myself why the object A has to dig to find stuff from object B and if and only if my model is correct ( dependencies are correct, have cohesion in the classes, etc... ) then I'd use the Observer pattern. That way you break the dependency between objects