DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Trending

  • Managing, Updating, and Organizing Agent Skills
  • Why Your AI Agent's Logs Aren't Earning Trust
  • Native SQL in Java Without JDBC Boilerplate — Meet Ujorm3
  • From "Vibe Coding" to Production: Setting Up an Evals Loop for Claude Agents
  1. DZone
  2. Coding
  3. Languages
  4. Taming the Moose: Method Modifiers Instead of Overrides in Object-Oriented Perl

Taming the Moose: Method Modifiers Instead of Overrides in Object-Oriented Perl

Using the override function may seem like the obvious choice when overriding a superclass’s method in the Perl Moose object-oriented framework. There may be a better way, though: method modifiers.

By 
Mark Gardner user avatar
Mark Gardner
DZone Core CORE ·
Aug. 31, 21 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
1.9K Views

Join the DZone community and get the full member experience.

Join For Free

Last month I wrote about using Moose's override function to, well, override a superclass's method. Chris Prather on the #moose IRC channel suggested soon after that the around method modifier (or its little sisters before and after) might be a better choice if you're also calling the original method inside. He noted that "at a minimum override only works if you're subclassing, around will apply to composing methods too."

His point was that when you decide to compose roles (also know as traits) instead of or in addition to more traditional inheritance, override simply doesn't work: only a method modifier will do. (And as Graham Knop and Karen Etheridge later remarked on IRC, override isn't even an option if you're using Moo as an alternative to Moose.)

Modifying a role's method with around might look like this:

Perl
 
#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::Role::Hungry;
use Moose::Role;
requires 'name';

sub wants_food {
    my $self = shift;
    say $self->name, ' is hungry!';
    return;
}

package Local::GuineaPig;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
    my ($orig, $self) = splice @_, 0, 2;
    say $self->name, ' runs to the front of the cage!';
    $self->$orig(@_);
    say 'Wheek!';
    return;
};

package Local::Dog;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
    my ($orig, $self) = splice @_, 0, 2;
    say $self->name, ' runs to the kitchen!';
    $self->$orig(@_);
    say 'Woof!';
    return;
};

before wants_food => sub {
    my $self = shift;
    say $self->name, ' is jumping!';
};

package main;
my $dog  = Local::Dog->new(name => 'Seamus');
my @pigs = map { Local::GuineaPig->new(name => $_) }
  qw<Cocoa Ginger Pepper>;

for my $animal ($dog, @pigs) {
    $animal->wants_food();
}

Running the above yields:

Seamus runs to the kitchen!
Seamus is hungry!
Woof!
Cocoa runs to the front of the cage!
Cocoa is hungry!
Wheek!
Ginger runs to the front of the cage!
Ginger is hungry!
Wheek!
Pepper runs to the front of the cage!
Pepper is hungry!
Wheek!

It's a little more involved than overriding a sub, since method modifiers are passed both the consumed role's original method ($orig above) and the instance ($self above) as parameters. It has the same effect, though, and you can call the original method by saying $self->$orig(parameters). That's why I used the splice function so I could pass any remaining parameters as the original @_ array.

If all you want to do is have something happen either before or after the original method, just use before or after:

Perl
 
before wants_food => sub {
    my $self = shift;
    say $self->name, ' is jumping!';
};

Note that there's no return value in a before or after modifier, as those are handled by the original method.

Modifiers aren't limited to consuming classes; they can be in roles and modify their consumers' methods. They also have a couple of other tricks:

  • You can pass an array reference to modify multiple methods at once.
  • You can use the contents of a variable to specify the modified method name, and use that same variable in the modifier itself.
  • You can use a regular expression to select methods. (Beware if you're using Moo that its Class::Method::Modifiers module doesn't support this.)

Putting these together gives you constructs like these:

Perl
 
after qw<foo bar baz> => sub {
    say 'Something got called';
};

for my $method_name (qw<foo bar baz>) {
    before $method_name => sub {
        say "Calling $method_name...";
    };
}

before qr/^request_/ => sub {
    my ($self, @args) = @_;
    $self->is_valid(@args) or die 'Invalid arguments';
};

Moose comes with great introductory manuals for method modifiers and roles, so be sure to check those out. There's a lot more to them and a blog can only cover so much.

Perl (programming language)

Published at DZone with permission of Mark Gardner. See the original article here.

Opinions expressed by DZone contributors are their own.

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook