oop intermediate

How to use delegation with handles in Perl Moose?

Question

How to use delegation with handles in Perl Moose?

In Perl's Moose object system, delegation is a powerful technique to forward method calls from one class to another wrapped object or attribute. Moose provides a convenient handles feature for attributes, allowing you to automatically delegate methods to the attribute's object without having to manually write forwarding methods.

What is Delegation with Handles in Moose?

Delegation means your object passes responsibility for some methods to an internal object it holds. Moose's handles lets you specify which methods from the attribute's class you want your class to "inherit" or expose transparently, reducing boilerplate.

For example, if your class has an attribute holding a HashRef, and you want to provide hash-like methods such as get, set, or keys directly on your object, handles makes it very easy.

Using handles with Moose Attributes

Moose attributes are declared with has. The handles option defines what methods from the attribute's class or role will be delegated. You can pass one of:

  • handles => 'method_name' - delegate a single method by the same name
  • handles => [ 'method1', 'method2' ] - delegate multiple methods
  • handles => { new_name => 'original_name', ... } - alias or rename delegated methods

Example: Delegation with handles in Moose

Below is a runnable example demonstrating delegation to a HashRef-like object. The class My::Config stores configuration in a hash reference and delegates get/set operations to the internal hash attribute.

use strict;
use warnings;
use 5.010;

use Moose;

package My::Config {
    use Moose;

    # The 'config' attribute holds a hashref
    has 'config' => (
        is      => 'rw',
        isa     => 'HashRef',
        default => sub { {} },
        traits  => ['Hash'],   # Use Moose's Hash trait for native delegation
        handles => {
            get_value    => 'get',     # delegate 'get' method to 'get_value'
            set_value    => 'set',     # delegate 'set' method to 'set_value'
            all_keys     => 'keys',    # delegate 'keys' method to 'all_keys'
            count_values => 'count',   # delegate 'count' method to 'count_values'
        },
    );
}

# Usage
my $conf = My::Config->new();

$conf->set_value('foo' => 42);
$conf->set_value('bar' => 99);

say "foo = ", $conf->get_value('foo');
say "bar = ", $conf->get_value('bar');
say "Keys stored: ", join(", ", $conf->all_keys);
say "Number of keys: ", $conf->count_values;

Explanation

  • The attribute config is a HashRef supporting delegation via the Hash native trait provided by Moose.
  • The handles hashes method names from the hash trait to the class methods, optionally renaming them for clarity.
  • Calling $conf->set_value('foo' => 42) delegates to $conf->config->set('foo', 42).
  • You can access the underlying hash functionality transparently through your class interface without manually writing methods.

Additional Notes and Pitfalls

  • Traits: Delegation like this requires the appropriate native trait (e.g., Hash, Array, or String) to be set on the attribute. Otherwise, methods like get or set won't exist.
  • Method Naming: You can rename delegated methods via the hashref form of handles to avoid collisions and improve readability.
  • Moose version: Native traits and handles have been stable since Perl 5.10 and Moose 2.x; make sure you have these or newer for best support.
  • Readonly Attributes: Delegation can be used with ro attributes too, but write methods won't work.
  • Overriding: If you need custom behavior, you can override delegated methods after declaration.

Summary

Delegation with handles in Moose is a concise, expressive way to expose functionality from contained objects or native traits on attributes. It reduces boilerplate and keeps your classes clean and focused on their own logic.

Remember to use the right trait (like Hash, Array) when delegating to native Perl data structures, and you can rename methods to your liking.

Verified Code

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

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
foo = 42
bar = 99
Keys stored: foo, bar
Number of keys: 2
STDERR
(empty)

Was this helpful?

Related Questions