Copyright Notice

This text is copyright by InfoStrada Communications, Inc., and is used with their permission. Further distribution or use is not permitted.

This text has appeared in an edited form in Linux Magazine magazine. However, the version you are reading here is as the author originally submitted the article for publication, not after their editors applied their creativity.

Please read all the information in the table of contents before using this article.

Linux Magazine Column 94 (Jun 2007)

[suggested title: ``The Moose is Flying (part 1)'']

Perl's object system is very ``flexible'', meaning, you get to build it from the ground up. You can build traditional hash-based objects, or more exotic array-based or inside-out objects. And then you have to create the accessors, define access policies, and perform a lot of repetitive code.

Luckily, Perl is introspective enough that you can get Perl to do most of the hard boring work. This has resulted in a number of ``class frameworks'' finding their way onto the CPAN. The Moose framework appeared about a year ago, and I initially dismissed it as ``yet another class framework'', much in the same way as I feel about yet another templating system or object-relational mapper.

However, I recently took a look at what Moose had become, and was pleasantly surprised. As I started playing with it, I exclaimed frequently that this framework would have saved me quite a bit of time on some past projects, such as the text I wrote for our Intermediate Perl course and book, parts of which have been included as the perlboot manpage in the distribution. Let's recreate the ``animal'' classes from that text, using Moose, to see how this emerging framework simplifies things.

First, we'll create a horse class in Horse.pm that has a name and a color:

  package Horse;
  use Moose;
  has 'name' => (is => 'rw');
  has 'color' => (is => 'rw');
  1;

Bringing in Moose defines has, which takes the name of an attribute along with its properties. Here, we're saying that the two attributes are ``read/write''. We can now use this class:

  use Horse;
  my $talking = Horse->new(name => "Mr. Ed");
  print $talking->name; # prints Mr. Ed
  $talking->color("grey"); # sets the color

Note that I didn't have to define a new method: Moose does that for me.

Now in the original text, Horse inherited from Animal. We can do that rather simply. In Animal.pm, we place:

  package Animal;
  use Moose;
  has 'name' => (is => 'rw');
  has 'color' => (is => 'rw');
  1;

And then update our Horse.pm:

  package Horse;
  use Moose;
  extends 'Animal';
  1;

Note that extends here replaces the traditional use base and completely sets @ISA, rather than adding to it. (It's possible that you might want to put this inside a BEGIN block, although I've not seen any examples requiring it yet.)

At this point, Horse and Animal are identical. They can both be instantiated, and have the two given attributes. In the original example, what distinguished a horse was the sound it made, which we can add here:

  package Horse;
  use Moose;
  extends 'Animal';
  sub sound { 'neigh' }
  1;

and then reference that in the common speak method in Animal:

  package Animal;
  use Moose;
  has 'name' => (is => 'rw');
  has 'color' => (is => 'rw');
  sub speak {
    my $self = shift;
    print $self->name, " goes ", $self->sound, "\n";
  }
  sub sound { confess shift, " should have defined sound!" }
  1;

Note the use of confess, another freebie from Moose. If the derived class hasn't defined a sound, I want to complain. But since Horse defines sound, I'll never see that for a horse. With this code, I can create my classic talking horse:

  my $talking = Horse->new(name => 'Mr. Ed');
  $talking->speak; # says "Mr. Ed goes neigh"

So far, I'm still coding things that would be simple without Moose, so let's start diverging a bit to see the full power. First, an Animal is really an abstract class, being used only to provide common attributes and methods to a concrete class (in this case, the horse class). In Moose-terminology, this can best be described as a role. A role is like a mix-in, providing a collection of attributes and methods that use those attributes. A role never has any instances, because it's not a complete class.

When we make Animal a role, we'll also get some additional support:

  package Animal;
  use Moose::Role;
  has 'name' => (is => 'rw');
  has 'color' => (is => 'rw');
  sub speak {
    my $self = shift;
    print $self->name, " goes ", $self->sound, "\n";
  }
  requires 'sound';
  1;

Note that we've replaced the confess-including stub with requires. This informs Moose that this role must now be used with a class that provides the sound method, which will be checked at compile-time. To pull in a role, we use with rather than extends:

  package Horse;
  use Moose;
  with 'Animal';
  sub sound { 'neigh' }
  1;

Had we failed to include sound, we'd get notification very early on. Cool. At this point, Horse otherwise still works as before.

What about those with and requires keywords? Because they're defined by the Moose and Moose::Role imports, they remain as part of the package. For the purists in us who don't like that kind of pollution, we can throw them away when we're done, using the correponding no keyword (similiar to use strict and no strict). For example, we'd clean up Horse.pm with:

  package Horse;
  use Moose;
  with 'Animal';
  sub sound { 'neigh' }
  no Moose; # gets rid of scaffolding
  1;

And similarly, Animal.pm requires no Moose::Role at the end.

Moose supports the notion of a default value. Let's add in the default color, and make that a class responsibility as well:

  package Animal;
  ...
  has 'color' => (is => 'rw', default => sub { shift->default_color });
  requires 'default_color';
  ...

If the color isn't provided, the default color of the class will be consulted, and requires ensures that the concrete class provides this default color. Our derived animal classes now look like:

  ## Cow.pm:
  package Cow;
  use Moose;
  with 'Animal';
  sub default_color { 'spotted' }
  sub sound { 'moooooo' }
  no Moose;
  1;
  ## Horse.pm:
  package Horse;
  use Moose;
  with 'Animal';
  sub default_color { 'brown' }
  sub sound { 'neigh' }
  no Moose;
  1;
  ## Sheep.pm:
  package Sheep;
  use Moose;
  with 'Animal';
  sub default_color { 'black' }
  sub sound { 'baaaah' }
  no Moose;
  1;

Now we can count sheep as one of our implemented classes:

  use Sheep;
  my $baab = Sheep->new(color => 'white', name => 'Baab');
  $baab->speak; # prints "Baab goes baaaah"

Well, this is pretty straightforward. Let's solve a few other problems from the original material.

The Mouse class was special, because it extended the speak method with an additional line of output. While we could use traditional SUPER::-based method calls to call parent-class behaviors, this doesn't work with roles. (Roles don't end up in @ISA, because they're ``glued in'' rather than ``tacked above''.)

Luckily, Moose provides the convenient after call to append additional steps to an existing subroutine. Moose does this by replacing the original subroutine with a new subroutine that calls the original routine and then calls the additional code. The context (list, scalar, or void) is properly preserved, as is the original return value. Our amended speak looks something like:

  package Mouse;
  use Moose;
  with 'Animal';
  sub default_color { 'white' }
  sub sound { 'squeak' }
  after 'speak' => sub {
    print "[but you can barely hear it!]\n";
  };
  no Moose;
  1;

This gives us a properly functioning mouse:

  my $mickey = Mouse->new(name => 'Mickey');
  $mickey->speak;

which results in:

  Mickey goes squeak
  [but you can barely hear it!]

We can also use before and around to precede the original behavior or control the calling of the original behavior, as necessary. For example, to allow name to be used as both an accessor and still return an unnamed Horse when used as a class method, we can ``around'' the resulting name accessor:

  package Animal;
  ...
  has 'name' => (is => 'rw');
  around 'name' => sub {
    my $next = shift;
    my $self = shift;
    blessed $self ? $self->$next(@_) : "an unnamed $self";
  };

The has creates the original behavior. The around intercepts the original subroutine name, causing the original coderef to be passed as the first parameter to this new subroutine, which we capture in $next. The original $self is shifted away, and tested to see if it's an object or not, via blessed (conveniently exported via Moose). For a blessed object, we get the original behavior (a getter or setter), but for a class, we'll get the literal string.

What if we never gave our animal a name? We'll get warnings about undefined values. We can give a default name just as we did a default color:

  has 'name' => (
    is => 'rw',
    default => sub { 'an unnamed ' . ref shift },
   );

Again, we'd want that around immediately following this step.

If we don't want people setting the color after the initial instance creation, we can declare the attribute as read-only:

  has 'color' => (is => 'ro', default => sub { shift->default_color });

Now an attempt to set the color is aborted with Cannot assign a value to a read-only accessor.... If we really wanted to have a way to occasionally set the color, we can define a separately named writer:

  has 'color' => (
    is => 'ro',
    writer => 'private_set_color',
    default => sub { shift->default_color },
  );

Thus, we can't change the color of a mouse directly:

  my $m = Mouse->new;
  my $color = $m->color; # gets the color
  $m->color('green'); # DIES

But we can use our private name instead:

  $m->private_set_color('green'); # sets the color to green

By using a long name, we're less likely to accidentally call it, except where we intentionally want to change the color.

Let's create a RaceHorse by adding ``race features'' to a Horse.

First, we define the ``race features'' as, yes, another role:

  package Racer;
  use Moose::Role;
  has $_ => (is => 'rw', default => 0)
    foreach qw(wins places shows losses);
  no Moose::Role;
  1;

Note that since has is just a subroutine call, we can use traditional Perl control structures (here, a foreach loop). With a bit of code, we've added another four attributes. The initial value of 0 means we don't have to write separate initialization code in our constructor. Next, we can add some accessors:

  package Racer;
  ...
  sub won { my $self = shift; $self->wins($self->wins + 1) }
  sub placed { my $self = shift; $self->places($self->places + 1) }
  sub showed { my $self = shift; $self->shows($self->shows + 1) }
  sub lost { my $self = shift; $self->losses($self->losses + 1) }
  sub standings {
    my $self = shift;
    join ", ", map { $self->$_ . " $_" } qw(wins places shows losses);
  }
  ...

Each call to won increments the number of wins. This would be simpler if we presumed that these objects are implemented as hashes (which they are by default), as:

  sub won { shift->{wins}++; }

However, by using the public interface (a method call), we could change the implementation later to inside-out objects or array-based objects without breaking this code. This is especially important when creating a generic role, which could be mixed in to any kind of object.

To create the race horse, we just mix a horse with a racer:

  package RaceHorse;
  use Moose;
  extends 'Horse';
  with 'Racer';
  no Moose;
  1;

And now we can ride the ponies:

  use RaceHorse;
  my $s = RaceHorse->new(name => 'Seattle Slew');
  $s->won; $s->won; $s->won; $s->placed; $s->lost; # run some races
  print $s->standings, "\n"; # 3 wins, 1 places, 0 shows, 1 losses

So far, I've just scratched the surface of what Moose provides. Next month, I'll look at some of the more advanced features of Moose that help keep the complex things relatively simple. Until then, enjoy!


Randal L. Schwartz is a renowned expert on the Perl programming language (the lifeblood of the Internet), having contributed to a dozen top-selling books on the subject, and over 200 magazine articles. Schwartz runs a Perl training and consulting company (Stonehenge Consulting Services, Inc of Portland, Oregon), and is a highly sought-after speaker for his masterful stage combination of technical skill, comedic timing, and crowd rapport. And he's a pretty good Karaoke singer, winning contests regularly.

Schwartz can be reached for comment at merlyn@stonehenge.com or +1 503 777-0095, and welcomes questions on Perl and other related topics.