Skip to content

Moose fairy dust

June 19, 2009

So following on from my last two posts (1)(2) about Moose Roles and Singleton Methods I thought it would be nice to know how Moose performs all this magic.

So to help explain all this I’ll create a simple (contrived!) example:

use MooseX::Declare;

class Animal {
    method walk { "unknown" }
    method wild { "wild?... I'm bliming livid!" }
}

Now if we introspect this:

my $baz = Animal->new;
say "baz is an Animal and its " . $baz->walk . " if he can walk or not?";
say "baz methods are: ", join " | ", $baz->meta->get_method_list;
say "baz ISA: ", join " | ", $baz->meta->class_precedence_list;

We will see this:

baz is an Animal and its unknown if he can walk or not?
baz methods are: walk | new | wild | meta
baz ISA: Animal | Moose::Object

Using get_method_list returns methods just in this class (running get_all_method_names would return all resolvable methods via inheritance).

And using class_precedence_list returns the class interitance chain starting with its own class Animal. NB. Moose::Object is the base class for all Moose objects.

So no surprises here. So what happens when I sprinkle some fairy dust on $baz by applying a role to this object (and creating a Singleton Method):

role DoesHuman {
    method walk { "when not drunk!" }
    method legs { 2 }
}

DoesHuman->meta->apply( $baz );

say "baz is now Human with " . $baz->legs . " legs and walks " . $baz->walk;
say "baz methods are: ", join " | ", $baz->meta->get_method_list;
say "baz ISA: ", join " | ", $baz->meta->class_precedence_list
say "baz says: ", $baz->wild;

This produces:

baz is now Human with 2 legs and walks when not drunk!
baz methods are: legs | walk | meta
baz ISA: Class::MOP::Class::__ANON__::SERIAL::2 | Animal | Moose::Object
baz says: wild?… I’m bliming livid!

First lets look at the object methods. legs has been added and walk has also nicely been replaced. So this does exactly what I asked it to do.

But hold on… where has wild gone from the method list? And yet when I do $self->wild it works fine??

Well if you followed Dave Thomas video link I gave in first post then this is easily explained (even though he’s talking about Ruby!).

If you look at the class inheritance you can see what happened. Here is my attempt to explain whats going on:

Applying DoesHuman role to $baz object has created new anonymous class called (in this instance) “Class::MOP::Class::__ANON__::SERIAL::2” and puts the DoesHuman role methods legs and walk into there and then makes this class a child of Animal. $baz is then assigned (blessed) to this new anon class.

Or has Dave Thomas says:

move one to the right and then up one

But that only makes sense if you use same diagrams he had!

All very neat! In a nutshell its created a unique anonymous class with the role methods which $baz uses instead of the Animal class.

And you can keep adding to this anon class chaining:

role DoesMale {
    method sex  { "male" }
    method wild { "nice to meet u!" }
}

DoesMale->meta->apply( $baz );

say "baz is now a " . $baz->sex;
say "baz methods are: ", join " | ", $baz->meta->get_method_list;
say "baz ISA: ", join " | ", $baz->meta->class_precedence_list;
say "baz says: ", $baz->wild;

baz is now a male
baz methods are: sex | wild | meta
baz ISA: Class::MOP::Class::__ANON__::SERIAL::3 | Class::MOP::Class::__ANON__::SERIAL::2 | Animal | Moose::Object
baz says: nice to meet u!

/I3az/

Some references:

  1. Roles, Singleton Methods & MooseX::Declare
  2. Using Moose Roles to create Singleton Methods
  3. Moose::Manual::MOP
  4. CLass::MOP::Class or (kobesearch)

Leave a comment