You are on page 1of 12

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 objectrelational 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 soundmethod, 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 nameto 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 readonly 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!

Linux Magazine Column 95 (Jul 2007)


[suggested title: ``The Moose is Flying (part 2)'']
Last month, I introduced the Moose object system by walking through the code
developed in the perlbootmanpage, rewriting it to use Moose. Continuing from that
discussion, let's look at some of the features I didn't cover last month.
Our Animal role included attributes of name, and color,
of speak and eat. We can add a birthdate attribute to the mix with:

and

actions

has 'born' => (is => 'ro');

As we don't want to be able to change the birthdate, we'll make it read-only. By


default, this attribute accepts any scalar, so these are all equally valid:
my
my
my
my

$horse = Horse->new(born => 'yesterday', name => 'Newbie');


$cow = Cow->new(born => 'spring of 82', name => 'Bessie');
$mouse = Mouse->new(name => 'Minnie', born => '3/14/1929');
$racehorse = RaceHorse->new(name => 'Slew', born => [3, 5, 59]);

We can get a bit of help from Moose to narrow down the permissible type of this
new birthdate attribute using Moose's typing system:
require DateTime;
has 'born' => (is => 'ro', isa => 'DateTime');

The isa parameter here declares that the born parameter must be a DateTime
object, or at least something that responds true to UNIVERSAL::isa($thing,
"DateTime").
Now, if we try to put anything in this born attribute other than a DateTime, we get a
run-time error. So, this fails:
my $horse = Horse->new(born => 'yesterday', name => 'Newbie');

But this succeeds:


my $horse = Horse->new(born => DateTime->now, name => 'Newbie');

The DateTime string for isa refers here to the Perl class. However, we can also
define this as an artificial Moose type:
use Moose::Util::TypeConstraints;
require DateTime;
subtype 'DateTime'
=> as 'Object'

=> where { $_->isa('DateTime') };

This works like before, but now identifies DateTime as a Moose-type. The type is
created by starting with any Object, and then requiring that this object pass the
additional qualification of being a subclass of Perl's DateTime.
At this point, we could continue to use this Moose-style DateTime type as we had
before. But once we've done this, we can further subtype the type. For example,
we can require that the date be a historical date (before now):
subtype 'HistoricalDateTime'
=> as 'DateTime'
=> where { $_ <= DateTime->now };
has 'born' => (is => 'ro', isa => 'HistoricalDateTime');

Now, not just any DateTime will do. It has to be something that isn't in the future.
The expression in wherecan be any expression returning a true/false value,
using $_ as a proxy for the object in question.
It'd be easier if we could still use casual forms like yesterday and 3/14/1929. These
are both understood by Date::Manip. We could parse the strings with Date::Manip,
then pull out the component values and hand them to DateTime, but luckily, there's
already a module to do that: DateTime::Format::DateManip.
use DateTime::Format::DateManip;
my $yesterday = DateTime::Format::DateManip>parse_datetime('yesterday');
my $newbie = Horse->new(born => $yesterday, name => 'Newbie');

Not bad. Our newbie horse is born yesterday, as we expect. But it'd be nice to just
drop yesterday into the slot and have it do all of that for us. And with coercions, we
can.
Since passing a simple string as the birthtime is illegal, we can inform Moose that it
should
take
that
string
and
run
it
through DateTime::Format::DateManip automatically:
coerce 'HistoricalDateTime'
=> from 'Str'
=> via {
require DateTime::Format::DateManip;
DateTime::Format::DateManip->parse_datetime($_);
};

The via code block takes $_ as the input value, which is expected to be a string
(Str).
The
last
expression
evaluated
in
the
code
is
the
new HistoricalDateTime value. We then permit this coercion to be used by
adding coerce into the attribute declaration:

has 'born' => (is => 'ro',


isa => 'HistoricalDateTime',
coerce => 1,
);

Now, the born slot accepts either an explicit DateTime as before, or a simple string.
The string must be acceptable to Date::Manip, which will be used to convert the
string into a DateTime object as our object is created.
my $newbie = Horse->new(born => 'yesterday', name => 'Newbie');
my $mouse = Mouse->new(name => 'Minnie', born => '3/14/1929');

Also, because the type constraint is still in place, the verification to ensure the
result is a historical date is still active.
Besides the named classes and Str, Moose::Util::TypeConstraints also establishes
types of things like Bool and HashRef.
We could even have multiple coercions defined, as long as they are distinct. For
example, we could use a hashref in the birthtime slot to indicate that we are
passing key/value pairs to be handed to a DateTimeconstructor directly:
coerce 'DateTime'
=> from 'HashRef'
=> via { DateTime->new(%$_) };

And now we can use a hashref to define the birthdate:


my $mouse = Mouse->new(
name => 'Minnie',
born => { month => 3, day => 14, year => 1929 },
);

If the value for born is a DateTime, it's used directly. If it's a string, it's passed
toDateTime::Format::DateManip. And if it's a hashref, it's passed directly as a
flattened list to theDateTime constructor. Very cool.
The value we specify for a default is subject to the same coercions and type
checking. We can updateborn as:
has 'born' => (is => 'ro',
isa => 'HistoricalDateTime',
coerce => 1,
default => 'yesterday',
);

And now our animals default to being ``born yesterday''. Note that the default value
is still subject to the type constraints, so if we replace yesterday with tomorrow, the
default value will be rejected properly. Note that the coercion happens as each

object is created, so a default value of one minute ago will give us a new time each
time it is called.
While we're on things we can do to attributes, another interesting item is lazy. If the
default value is expensive to compute, we can say ``don't really do this until you
need to do it''. For example, turningyesterday into a DateTime is slightly expensive,
so we can flag that as lazy:
has 'born' => (is => 'ro',
isa => 'HistoricalDateTime',
coerce => 1,
default => 'yesterday',
lazy => 1,
);

Speaking of great support, as I was writing that last paragraph, I noticed a bug in
the result, and chatting with Stevan on IRC got it fixed before I could turn this
article in. Yeay.
Anything built with Moose has a very high degree of introspection available. For
example, we can ask one of our animal friends to give us the meta object, with
which we can make further requests:
my $horse = Horse->new;
my $meta = $horse->meta; # or equivalently, Horse->meta

$meta is a Moose::Meta::Class. We can ask the horse for the roles:


my @roles = @{$meta->roles};

In this case, we see that we've mixed in one role (of type Moose::Meta::Role, and
get the name with:
map { $_->name } @roles; # qw(Animal)

which gives us Animal as we might expect. We can also ask the meta object for all
applicable methods:
my @methods = $meta->get_method_list;

which returns
BEGIN
born
color
default_color
eat
meta
name

private_set_color
sound
speak

Nice. Not sure what BEGIN is doing in there, but the rest are things that we've
defined. Many of these methods relate to the attributes, but we'd can query those
definitively usingcompute_all_applicable_attributes instead:
my @attrs = $meta->compute_all_applicable_attributes;

The result is a set of Moose::Meta::Attribute objects. We can map them


through name as before to get the names:
map { $_->name } @attrs; # qw(born color name)

We can also see if they have setters:


grep { $_->has_writer } @attrs; # qw(color)

Note that only color has a setter: the other two are read-only, so this makes sense.
As noted above, Moose is still being actively developed, but is production ready as
long as you stick with things that work. You'll find the latest Moose in the CPAN,
along with some other core plugins, typically in the MooseX namespace.
For example, MooseX::Getopt allows you to define your @ARGV processing using
type coercion, type constraints, and all that jazz. I haven't had time to play with that
yet, but it's on my to-do list, so perhaps I'll cover that in a future column.
Similarly, MooseX::Object::Pluggable makes it easy to write classes that
are pluggable, meaning that they can work well with plugins that define additional
methods and attributes. (Think of a generic web server or IRC bot object that has
individually selectable additional behaviors.) Again, I'm just noticing these, and they
look like they are worthy of their own descriptions later.
Also note that Moose is itself built on Class::MOP, which is a framework for making
class frameworks. Perhaps other projects besides Moose will be using Class::MOP
as
a
starting
point
as
well.
For
example,
the
infrastructure
of Class::Prototyped (which I use in my own CGI::Prototype) might be built
onClass::MOP, giving it more flexibility and robustness.
I hope you've enjoyed this two-part introduction to Moose. Have fun playing with a
production-ready flexible object-building system. Until next time, 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.

You might also like