http://www.perlmonks.org?node_id=915250


in reply to Why does changing a Moose attributes' properties remove the around modifier

Changing the properties of the base class' accessor removes the around modifier defined in the base class. When I simply inherit the base class without modifying it, however, the around modifier fires off properly.

Actually, it is not removing the 'around' modifier, you are simply creating a new accessor in your derived class, which itself is not around-ed. Allow me to explain ...

When you create an attribute, Moose compiles the accessor methods for you and installs them in the package in which they are defined. These accessor methods are nothing magical (in fact, nothing in Moose is very magical, complex yes, but magical no), and so they are inherited by subclasses just as any other method would be.

When you "around" a method (as you are doing here) Moose will extract the sub from the package, wrap it and replace the original with the wrapped version. This all happens in the local package only, the method modifiers do not know (or care) anything about inheritance.

When you change an attributes definition using the +attr form, Moose looks up the attribute meta-object in the superclass list and then clones that attribute meta-object, applying the changes you requested and then installs that attributes into the local class. The result is that all accessor methods are re-compiled into the local class, therefore overriding the ones defined in the superclass.

Make sense?

-stvn
  • Comment on Re: Why does changing a Moose attributes' properties remove the around modifier
  • Download Code

Replies are listed 'Best First'.
Re^2: Why does changing a Moose attributes' properties remove the around modifier
by mcrose (Beadle) on Jul 18, 2011 at 18:56 UTC

    It does; and I figured something like that was what was going on. I'm just surprised that the metaobject protocol doesn't account for inherited wrapper methods when figuring out a derived class' accessor code. Is there any way to direct Moose to continue using the superclass's around modifier, or is this intended to be the correct way of modifying an accessor's result when expecting inheritance that modifies the metaobject?

    use strict; use warnings; use 5.010; package My::Base; use Moose; has 'attr' => (is => 'ro', isa => 'Str', required => 1, reader => '_at +tr'); sub attr { my $self = shift; return "The value of attr is '".$self->_attr."'" }; package My::Derived; use Moose; extends 'My::Base'; has '+attr' => (required => 0, lazy_build => 1); sub _build_attr { return "default value"; } package main; use Test::More tests => 6; use Test::Exception; throws_ok {My::Base->new()} qr/Attribute \(attr\) is required/, q/base + requires 'attr' at construction/; my $base = new_ok('My::Base' => [attr => 'constructor value']); cmp_ok($base->attr, 'eq', "The value of attr is 'constructor value'", +'base is correct'); lives_ok {My::Derived->new()} q/derived doesn't require 'attr' at cons +truction/; my $der = new_ok('My::Derived'); cmp_ok($der->attr, 'eq', "The value of attr is 'default value'", 'deri +ved is correct');

      I stated a lot of that badly, but after reflection, no it makes total sense that the original code doesn't work as-is, and that it needs to be gotten around by creating a shim subroutine that gets inherited down the object hierarchy that runs against the Moose-built accessor. You can disregard the question.

      It would, however, be pretty nice if Moose could support this sort of behavior natively and have it just work, instead of requiring that sort of workaround. Not conversant in the nuts and bolts of the Class::MOP internals, however, I'm not sure if such a thing is possible.

        It would, however, be pretty nice if Moose could support this sort of behavior natively and have it just work, instead of requiring that sort of workaround.

        Well, it has been discussed before, the idea of inheriting method modifiers in subclasses, but the determination always is that this would be dangerous action at a distance. If you want to override a method in a subclass you should not need to worry about whether one of the superclasses in the chain has a method modifier attached to it. While this might be behavior you want now, it is most certainly not a good generic behavior and since method modifiers are generic things, ... you get the idea here.

        I would be interested to know what problem you are trying to solve by using an around on an attribute accessor. Often times this kind of stuff can be solved using some other feature of Moose attributes.

        -stvn