Modifing inherited accessors and retaining around modifiers
I'm trying to inherit and extend a base class with a more specific child class that removes the required attribute from an accessor and specifies a lazily b开发者_StackOverflowuilt default. However, when doing so, the derived class no longer wraps the around subroutine around calls to the accessor.
What am I doing wrong in my definition?
Edit: I should state that I can simply inherit the accessor without modifying it and the around modifier still works, and I'm aware I can do something like set the accessor to have a getter, then define a getter method with the name of the accessor (i.e. sub attr { my $self = shift; my $value = $self->_get_attr; return "The value of attr is '$value'"; }
). I'm simply surprised the around modifier gets dumped so easily.
use strict;
use warnings;
use 5.010;
package My::Base;
use Moose;
has 'attr' => (is => 'ro', isa => 'Str', required => 1);
around 'attr' => sub {
my $orig = shift;
my $self = shift;
my $response = $self->$orig(@_);
return "The value of attr is '$response'"
};
package My::Derived;
use Moose;
extends 'My::Base';
has '+attr' => (required => 0, lazy_build => 1);
sub _build_attr {
return "default value";
}
package main;
my $base = My::Base->new(attr => 'constructor value');
say $base->attr; # "The value of attr is 'constructor value'"
my $derived = My::Derived->new();
say $derived->attr; # "default value"
Per a response from stvn for the same question on perlmonks, the issue is:
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.
It doesn't go the other way around, where the accessor is built from the bottommost class in the ISA, then the around modifiers up the ISA stack are applied in turn.
精彩评论