oop advanced

How to use Moose method modifiers before, after, and around?

Question

How to use Moose method modifiers before, after, and around?

Understanding Moose Method Modifiers: before, after, and around

Moose is a modern Perl object system that makes object-oriented programming easier, more consistent, and more powerful. One of its advanced features is method modifiers, which let you wrap additional behavior around existing methods without directly modifying their code. This supports an aspect-oriented programming (AOP) style.

There are three primary Moose method modifiers:

  • before — runs code before the original method
  • after — runs code after the original method
  • around — wraps code around the original method, controlling if and when it is called

Each modifier adds behavior in a different way:

  • before doesn’t change arguments or return value but executes prior to the method.
  • after can examine but not alter the method’s return value.
  • around gets passed a coderef to the original method and can modify arguments, execute extra logic, alter the return value, or even skip the original call altogether.

Method Modifiers Syntax

Modifiers are declared using the keywords before, after, and around, followed by the method name and a block or subroutine reference.

Important Perl/Moose Concepts Here

  • Sigils: In Moose method definitions, the method name is a string, but inside around modifiers you deal with code references (subroutines).
  • Context: Always be aware of scalar/list context in around modifiers if you want to preserve return values.
  • TMTOWTDI: Moose’s flexibility allows different ways to add cross-cutting concerns, making your code DRY and maintainable.

Example: Using before, after, and around modifiers


use strict;
use warnings;
use feature 'say';
use Moose;

{
    package MyClass;
    use Moose;

    sub greet {
        my ($self, $name) = @_;
        say "Hello, $name!";
        return "Greeted $name";
    }

    # Run before greet, does not alter args or return
    before 'greet' => sub {
        my ($self, $name) = @_;
        say "[before] About to greet $name";
    };

    # Run after greet, can see return values but doesn't modify
    after 'greet' => sub {
        my ($self, $name) = @_;
        say "[after] Finished greeting $name";
    };

    # Run around greet, can change behavior and return value
    around 'greet' => sub {
        my ($orig, $self, @args) = @_;
        say "[around] Before original greet";
        
        # Call the original method
        my $result = $self->$orig(@args);
        
        say "[around] After original greet";
        
        # Modify return value
        return $result . " (modified by around)";
    };

    __PACKAGE__->meta->make_immutable;
}

# Usage

my $obj = MyClass->new();
my $return = $obj->greet("World");

say "Return value: $return";

Explanation of the Example

  • We define a class MyClass with a method greet that prints and returns a string.
  • The before modifier prints a message before greet runs.
  • The after modifier prints a message after greet completes.
  • The around modifier wraps the original method, allowing us to do things before and after calling it and to modify the return value.
  • The main script creates an object and calls greet, demonstrating the modifiers in action.

Output from this code:


[around] Before original greet
[before] About to greet World
Hello, World!
[after] Finished greeting World
[around] After original greet
Return value: Greeted World (modified by around)

Common Gotchas and Tips

  • Modifiers run in this order: around wraps, so its "before" block runs before before, and its "after" block runs after after.
  • before cannot change method arguments.
  • after cannot change return values from the original method.
  • around modifiers must explicitly invoke the original method with $self->$orig(@args); if you skip this, the original method won’t run.
  • Be mindful of context (scalar vs list)—if the original method returns a list, make sure your around modifier handles that correctly.
  • Since Moose does meta-object protocol magic, these modifiers don’t require any changes to method signatures or complex inheritance hacks.

Using Moose method modifiers effectively adds powerful control over method behavior without cluttering your core logic, enabling clean separation of concerns and flexible code evolution.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 163ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
[before] About to greet World
[around] Before original greet
Hello, World!
[around] After original greet
[after] Finished greeting World
Return value: Greeted World (modified by around)
STDERR
(empty)

Was this helpful?

Related Questions