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

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');
  • Comment on Re^2: Why does changing a Moose attributes' properties remove the around modifier
  • Download Code

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

    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

        I use it for keeping objects internally with implicit error checking as anything uncoercible dies, but not exposing them externally. For a contrived example, something like:

        has [ qw/server peer monitor netlog/ ] => ( is => 'ro', isa => 'NetAdd +r::IP', coerce => 1, required => 1 ); coerce 'NetAddr::IP' => from 'Str' => via { NetAddr::IP->new($_, '255. +255.255.255') }; around [ qw/server peer monitor netlog/ ] => sub { my $orig = shift; my $self = shift; my $netaddr_ip = $self->orig(@_); return $netaddr_ip->addr; };

        The above accepds valid single IPs (v4 /32 and v6 /128) and passes them back out as addresses, but avoids the default stringification (CIDR notation) the object by default resolves to. Using the lists w/ around is shorter and easier to read as I don't need to make a seperate shim stub for each object's accessor and means it's less likely future refactoring will forget to stringify the accessor appropriately.

        However, it's not possible to make a more specific derived class instance with default IPs for some values as it kills the 'around' modifier.

        I mean, it's easy enough to say that 'you get an object back, deal with it B)' but if I can inflate passed things to objects as they come in and deflate them back to strings as they go out, why not do it?

        Edit:Actually, why not just add a 'decoerce' or 'deflate' or something to the accessor, a coderef that gets run against a value as the value is being returned? It'd allow a (deflate => sub { $_->clone }) to be applied to a DateTime accessor, for example, to make sure a end user doesn't ->add() to your internal value, etc, while not being spooky action at a distance; it's just another attribute of the accessor that can be changed or ignored or overridden by inheriting classes.