Thoughts on parametrized roles for Moose

July 15th, 2008

Moose is your favorite meta-object system in your favorite language of choice. And you already have a lot of excellent concepts that extend the basic usage of object-oriented programming, like having simple means to override parts of methods (around, before, after) and of course roles.

Roles are great, I even used them for my logging needs in MooseX::Log::Log4perl as stated earlier. After getting getting feedback by Micheal Schilli to add an easier interface for simple logging needs I had two choices to accomplish that:

  • Add another role (and reuse the initial role) like it is implemented currently in MooseX::Log::Log4perl::Easy:

    package MooseX::Log::Log4perl::Easy;
    use Moose::Role; ### Make it a moose role
    with 'MooseX::Log::Log4perl'; ### Reuse the base role with its attributes and methods
    sub log_fatal { my $self = shift; $self->logger->fatal(@_); }
    sub log_error { my $self = shift; $self->logger->error(@_); }
  • Use a method alias by using import to have a function returning the correct role to use with with. This is exactly what MooseX::Storage does to allow parametrized loading of moose roles to save some typing for lazy people and improving readability.

    use Moose;
    use MooseX::Storage; ### You have to use it to allow import to provide you the Storage alias
    with Storage('format' => 'JSON', 'io' => 'File'); ### Use the function to return the correct roles

The first approch clutters my module package a little, also requiring more documentation and hinting for people to find the module (more of a problem for lazy people like me).
The downside of the second approach is, that you have to use MooseX::Storage first, to have the Storage function exported. And it does not really look like the standard way of adding a role to the object, which is usually defined using quoted string like with 'MooseX::Log::Log4perl'; (note the quotes here).
A solution to that problem might be adding another keyword function to moose e.g. called role that makes use of some import magic and returns the correct role packages to load, also calling role initialization method, that allows to do some role tricks.

use Moose;
with role 'My::Role'; ### no magic here same as: with 'My::Role';
with role 'MooseX::Log::Log4perl' => ':easy'; ### pass a param
### or even
with role 'MooseX::Log::Log4perl', prefix => 'mylog_'; ### pass the param hash/pair to a role

The role keyword would return the correct role method to load, and additionally allow the role to initialize and use the prefix parameter to do some additional initialization, even if that would mean only setting a “_role_param attribute” that could be used later in default coderefs. Using this, would mean that you cannot use multiple roles with the with role keywords, but that’s ok for me, since perl users are used to that anyway, it’s the same for use.

Comments are closed.