Gist of the Day: Roles in Moose!

Have you ever struggled with how to structure your class hierarchy, given a common type of functionality which applies to some classes but not others? Say for instance you have a class named Animal. With this Animal class you can derive all of your animal classes. Take for instance a chicken, for which you subclass Animal to a class you call Chicken.
One of the features you’d like to implement is that an animal makes a noise. Chickens, for instance, cluck. Some animals, however, don’t make a noise. Take a seahorse for instance, it doesn’t make noise. It is every bit an animal, but it doesn’t make noise. There are many other mute animals across many different families of animals, so it doesn’t really seem to fit in to your hierarchy. For this purpose, you can use a Role in Moose. A role allows you to dynamically add functionality to an existing Moose class (as many of them as you like) without having to mangle your nice, clean class hierarchy. Think of it as a grab-bag of functionality for your class which can also be used by other classes regardless of their parentage.

Here, have some code

Here’s your Animal class:
[gist id=”6417632″ file=”Animal.pm”]
And here’s your Chicken class:
[gist id=”6417632″ file=”Chicken.pm”]
Here’s the Role we create for noisy animals:
[gist id=”6417632″ file=”Noisy.pm”]
And here’s the program to demo the whole thing:
[gist id=”6417632″ file=”animal_prog.pl”]

Here’s why you might care

With the Animal, you see I give it only a name attribute. Surely there’s a bunch of other stuff that you could attribute to animals than that, I’ll let you expand attributes as you see fit 🙂
For Chicken, I already know what the animal name is so I override the name attribute to have a default of “chicken”. For a moment, skip past the with and after portions, we’ll come back to those.
For the Noisy class, notice that I use Moose::Role, that right there makes this a role. Now, in the Noisy class I make one method, make_noise(). This method starts the phrase of what the animal says, and gives us a hook on which we can add functionality. Since the chicken makes a specific noise, we’ll want to use that hook to say exactly what the animal says.
Now, go back to the Chicken class for a moment. The with statement loads the Noisy module and then binds in the role using all of that Moosey magic. Then, the after statement binds to the make_noise() method of the Noisy role and causes this anonymous function to be executed immediately following the code defined by the role. In this specific case that means that make_noise() defined in Noisy outputs "The chicken says: " and then the Chicken class’ binding to the make_noise() method says "bok bokn".
Now look at the animal_prog.pl program. What’s really cool about roles is that you can tell whether or not an instance uses a specific role using the does() method. This method takes a role’s class name and returns true or false depending on whether the specified role is used or not.
Here’s the output of the program:

seahorse
chicken
The seahorse doesn't really say much.
The chicken says: bok bok.

In Closing

Moose is full of neat little things like this which help to reduce boiler-plate code. Reducing this repetitive code helps to reduce the amount of code you have to write and it also helps to reduce bugs.
I hope you found this write-up useful. I have been enjoying posting these.

2 Replies to “Gist of the Day: Roles in Moose!”

  1. Just a note, in your Chicken class, you do not need to repeat the ‘is => rw’ and the ‘isa => Str’ options in your attribute, the ‘+name’ form will do that for you already.
    – Stevan

Leave a Reply to Stevan Little Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.