In our classes we have a pattern where we create an attribute to represent a calculated value. For obvious reasons we want to cache the calculated value and then invalidate the cache when one of the underlying values change.
So we currently have this:
package FooBar;
use Moose;
has 'foo' => (
accessor => {
'foo' => sub {
my $self = shift;
if (@_ > 0) {
# writer
$self->{foo} = $_[0];
# reset fields that are dependant on me
$self->{bar} = undef;
}
# reader part;
return $self->{foo};
}
}
);
has 'bar' => (
accessor => {
'bar' => sub {
my $self = shift;
if (@_ > 0) {
# writer
$self->{bar} = $_[0];
}
# reader part;
$self->{bar} = calculate_bar($self->foo, $self->baz)
if (not defined($self->{bar}));
return $self->{bar};
}
}
);
sub calculate_bar { ... }
This long hand method is getting very tedious and error prone when calculated values depend on other calculated values.
Is there a smarter/simpler way for 'bar' to monitor the attributes it depends on vs having 'foo' know who is dependent on it? Also how can I avoid setting bar via hash member access?
Would this work?
Output:
If I understand you correctly, you can use triggers to clear attributes when one is set. Here's an example:
So, any writes to
foo
via$obj->foo($newvalue)
will causebar
to be cleared, and recreated on next access.I think it is quite possible that you're making this harder on yourself by using an Attributes implicit memoization with lazy, when you could just make the memoization explicit making your whole program more transparent
See cpan's Memoize for information and control of the internal cache, also remember that a Memoized function can not be dependent on the state of the object. So the arguments must be passed in explicitly.
I haven't done any poking around in Moose internals and the meta object protocol, but I think this is a good time to do it.
You want to patch the code generation so that when you specify an attribute as
the code generation phase creates code for the
foo
andbar
attributes as you specified above.How to do this is an exercise left to the reader. If I had a clue, I'd try to give you a start. Unfortunately, all I can advise you with is "This is a job for the MOP".