Is there any way in Moose of triggering a callback when the content of an attribute is changed via reference instead of setting its value via mutator?
Let's assume the following code:
has _changed => ( is => 'rw' , isa=>'Bool' ) ;
has attribute => (
is=>'rw', isa=>'Maybe[HashRef]',
default => sub { { a => 1 , b => 2 } },
trigger => sub { shift->_changed(1) }
) ;
the trigger works as expected setting the attribute value through mutator:
$self->attribute({ a => 2 , b => 2 }) ; # OK
but setting directly a value through its key then the trigger doesn't fires (of course):
$self->attribute->{a} = 3 ; # KO
I discarded the idea of creating (and comparing) a digest of serialized attribute's content, because it can be a very huge hashref with several nesting levels, and making a digest at every attribute access can produce a performance issue.
A tied hashref (as attribute value) could be a possible solution? Any idea or suggestion is very appreciated.
NOTE: The structure of contained hashref is not known (I'm writing an ORM class, so the struct can vary depending on documents stored on NOSQL db side).
Once you change the hash ref directly rather than using accessor methods, Moose is no longer involved. Having your attributes return a reference to a tied hash would be the only strategy to make changes to the hash observable, yet this is not a particularly attractive solution. Tied variables are rare and likely to trigger bugs in some code. They are comparatively difficult to implement. And they imply a performance overhead for every hash access.
Strongly consider whether you can change your design to avoid exposing the internal hash. E.g. have a getter that only returns a (shallow) copy of the hash, and a setter for individual elements in the hash. You may be able to autogenerate some of these accessors using the handles
and traits
mechanisms, e.g. see Moose::Meta::Attribute::Native::Trait::Hash.