oop intermediate

How to implement method delegation in Perl Moo?

Question

How to implement method delegation in Perl Moo?

In Perl object-oriented programming, Moo is a lightweight object system providing many modern OO features. One common pattern is method delegation, where an object forwards method calls to an attribute’s underlying object, reducing boilerplate code.

With Moo, you can easily implement delegation using the handles attribute option when defining an attribute. This instructs Moo to automatically create delegation methods in your class that forward to the attribute’s methods.

How to Use handles in Moo for Delegation

You define an attribute that holds an object and specify which methods it should delegate by passing method names or method name mappings in the handles attribute option.

  • handles => ['foo', 'bar'] delegates calls for foo() and bar() to the contained object.
  • handles => { new_name => 'original_name' } lets you rename the delegated method.
  • Delegation helps encapsulate components cleanly, avoids repetitive wrapper methods, and supports composition over inheritance.

Perl Code Example

use strict;
use warnings;
use feature 'say';
use Moo;

# This class represents a Logger object
package Logger {
    sub new { bless {}, shift }
    sub log_info { my ($self, $msg) = @_; say "[INFO]: $msg" }
    sub log_warn { my ($self, $msg) = @_; say "[WARN]: $msg" }
}

# This class contains a Logger and delegates logging methods to it
package MyApp {
    use Moo;

    has logger => (
        is      => 'ro',
        default => sub { Logger->new },
        handles => {
            info => 'log_info',   # delegate info() -> log_info()
            warn => 'log_warn',   # delegate warn() -> log_warn()
        },
    );

    sub run {
        my ($self) = @_;
        $self->info("Starting application");
        $self->warn("This is just a warning");
    }
}

package main;

my $app = MyApp->new;
$app->run;

Explanation:

  • Logger is a simple class with log_info and log_warn methods.
  • MyApp has a logger attribute holding a Logger object. The attribute uses handles to delegate info and warn methods to those in Logger.
  • When calling $app->info(...), it actually calls $app->logger->log_info(...) transparently.
  • This avoids writing explicit forwarding methods, following the Perl motto TMTOWTDI (There’s More Than One Way To Do It) elegantly.

Key Points about handles Delegation in Moo

  • Sigil Note: The attribute is accessed as $self->logger internally. The delegated methods belong to the attribute’s object.
  • Delegation can be to a single method (as string), a list of methods (array ref), or a hash ref for renaming.
  • Attempting to delegate to a method not present in the delegated-to object will raise an error at runtime.
  • Moo supports lazy attribute building, so delegation works smoothly with lazy attributes too.
  • This feature has been stable since early Moo releases (perl 5.10+ compatible).

Common Pitfalls and Gotchas

  • Delegation only works if the attribute contains a valid object implementing the delegated methods.
  • Make sure to declare the delegated methods correctly—typos lead to runtime errors.
  • You can delegate only instance methods, not class methods.
  • You cannot delegate to functions or packages that are not objects.
  • If you override delegated method names manually in your class, delegation methods might be overridden.

In summary, method delegation in Moo is straightforward and a great way to compose behavior by forwarding methods from contained attributes. Using the handles option with your attributes lets you keep your classes concise, readable, and maintain a clean separation of responsibilities.

Verified Code

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

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
[INFO]: Starting application
[WARN]: This is just a warning
STDERR
(empty)

Was this helpful?

Related Questions