Search code examples
perlmooserolemethod-modifier

Why doesn't Moose role application with method modifiers work in my code?


I have a Role and several classes that mix-in the role. The Role class loads all of the implementing classes so that anything that imports Blah can use them without typing a lot of 'use' lines.

package Blah;
use Moose::Role;

use Blah::A;
use Blah::B;
(etc...)

requires '...';
requires 'foo';
around 'foo' => sub { ... }

A typical Blah subclass:

package Blah::A;
use Moose;
with 'Blah';

sub foo { ... }

__PACKAGE__->meta->make_immutable;

Since every subclass 'foo' method starts with the same bits of code, the role also implements these via a method modifier.

Problem is: Moose doesn't apply the method modifier to any of the Blah::* classes. This happens even if I remove the make_immutable call for the classes. I thought role application was done entirely at runtime, and so even though the Blah::* classes are loaded before Blah, the modifier should still be applied?

I'm looking for a fix, or an alternate way of doing things. At the moment Blah is essentially an abstract base class except for the method modifier, which is why I used roles to begin with - but maybe a class hierarchy would be better? Thanks in advance.


Solution

  • Your call order is a little odd -- why are you useing Blah::A from within the role that is then applied to Blah::A?

    I would suggest pulling out these use lines and moving them to where they are actually needed (in the caller(s)). Get the code working first, and after that, if you have lots of use lines cluttering things up everywhere, you could move them off into an Includes file.

    But no, in answer to your assumption -- role application is not done at runtime, but at whatever time the with line is encountered. If you use a module at compile-time, then that file is compiled immediately, and the with line executed (which then forces the role to be compiled, and then it is run). You can of course apply a role at runtime as well (e.g. see apply_all_roles in Moose::Util), but that is not what is happening here.