A small trick to make “before” a bit more powerful, a bit more useful, and a bit more dangerous.

In Moose, the “before” and “after” method modifiers normally don’t affect the method they are modifying. But I’ve always wish that I could. Specifically, I wish “before” could take in and modify the parameters, and “after” could take in and modify the return value.

Today I learned that I can partially get my wish.

Look at the below code.

package Muppet;
use Moose;

has 'name' => (is =>; 'rw', isa => 'Str');

before 'BUILDARGS' => sub {
    shift; # ignore the class name
    my $args = shift; # get the construction arguments
    $args->{name} = "miss piggy"; # change the name
};

package main;
use feature 'say';

my $me = Muppet->new({name => "kermit"});
say $me->name; # will say "miss piggy"

In this code we set the name to “kermit”, and in a before block alter the parameter.

The reason why this works is simple. Since the argument is a hash reference, Perl will pass the argument via pointer, not via deep copy. So you can alter the contents of the hash reference, and the final BUILDARGS will pick it up.

Although this is a small edge case, it does hit a common use case for me, I’m always overriding BUILDARGS to make simple adjustments to the arguments coming in. Normally I have to override the method and make sure I use the SUPER correctly. With a simple “before” modifier, there’s one less line of code for me to screw up.