by Chris Prather

A question came up recently on a mailing list. I was talking about how Roles are a awesome win for Perl5 considering how few languages implement the concept1. Someone asked what the win was with Roles. I happen to have been thinking about this recently and dashed off a reply.

When you use Inheritance, especially multiple inheritance, for behavioral re-use you run into several problems quickly.

First Inheritance is an explicit modeling of a relationship that carries semantic meaning. Let's say you're developing a game for Biology students to explain to them taxonomy. In this game a Dog class is a subclass of Animal. That is, the Dog class inherits specific behaviors and attributes from the Animal class. This probably isn't even a direct relationship your Dog class may inherit from a Mammal class which inherits from a Vertebrate class which inherits from Animalia which itself inherits from Life. These kinds of hierarchies are common in Taxonomy as well as in Object Oriented programming. However when you need to express something that may cross cut concerns in, you run into issues.

Say for example your marketing department has had trouble selling this product to schools and is attempting to market to parents directly. They have done studies and kids really like Pets2. So your boss comes to you because the company wants you to add the concept of Pet to your Taxonomy model.

Pets don't fit into a Taxonomy, it's obvious that not all Animalias are Pets3 and some Pets may not be animals at all4. In many languages can use Multiple Inheritance to describe this new "I'm an Animalia and a Pet" relationship but often you run into issues there as well. Is a Pet a Life? That would mean our object model would look like:

Life
Animalia
Vertebrae
Canine    Pet
Dog

Pet stands out like a sore thumb. Obviously we've got issues with this new modeling. We talk to our boss and figure out that the rules for Pet are simple. Pet's are always domesticated versions of the Animalia, but not every class in Animalia is a pet. So for example Dogs are always Pets, Wolves are not. We can solve this with multiple inheritance now, but it's really not a clean way to express the relationship and it requires us to document the special relationship the Pet class would have with the rest off the Inheritance tree. Once you get beyond a few "special cases" like this it becomes hard to see the model for the exceptions.

This is why some languages like to disallow multiple inheritance entirely. In Java for example, Pet could become an Interface.

public interface Pet {
Date getYearDomesticated;
}

This however means that every class that we want to be a pet needs to have the exact same piece of boiler plate code added to it.

class Dog implements Pet {
...
private Date yearDomesticated;
public Date getYearDomesticated () { this.yearDomesticated }
...
}

If we instead have the concept of Roles then we can apply the concept of a Pet once at any level of the hierarchy we need. A example using a modern Perl5

package Pet {
use Moose::Role
has year_domesticated => (
is => 'ro',
isa => 'DateTime',
required => 1
);
}
package Dog {
use Moose;
extends qw(Canine);
with qw(Pet);
}

The Pet Role here implements everything we need for a default implementation, and doesn't require more boiler plate to our Dog class, that the bare minimum needed. It also avoids the ugly inheritance issues we saw with multiple inheritance by moving the behavior composition onto different tool. In my opinion, Roles aren't a win for every use of inheritance, nor for every time you want to re-use behavior, but they are an excellent tool to have in the box and one that the Moose crowd knows to reach for quite often.


  1. Off the top of my head I only know about Perl5, Perl6, Scala, Javascript, and Smalltalk. There may be other implementations out there. ↩

  2. The Marketing guy's daughter plays on WebKinz nightly. ↩

  3. Pet Shark's would be dangerous to say the least, and where would you keep a pet Blue Whale? ↩

  4. Who doesn't love their Pet Rock? ↩

  5. We're using the the inline package syntax that will be released in 5.14 ↩

Chris Prather is an Owner at Tamarou LLC, a member of the Moose cabal, and responsible for Task::Kensho.