Moose: A postmodern object system for Perl 5

Moose is a complete object system for Perl 5. It provides a simple and
consistent syntax for attribute declaration, object construction and
inheritance, without the need to understand how those things are
implemented. Furthermore, Moose allows you to separate the use of your
data from its underlying representation, thus you need not know whether
Moose is using a hash, array or something else in which to store your data.
This allows the programmer to focus on ``what'' the code is doing, rather
than ``how''.

The basics

Using Moose gives us more easy accessors, clever classes, roles, types and
coercions and loads of other cool stuff. However the basic OO rules
still apply.

A class is just a package

To create a class in Perl we create the package and use the Moose
module:

package PlayingCard;
use Moose;
# we now have a Moose-based class
1;

That's it! Moose also turns on strict and warnings for us, so we
don't have to do that ourselves, although nothing bad happens if we
turn them on explicitly.

Classes in Moose can be used straight away, as it establishes a
constructor for us automatically. Admittedly our class isn't
very useful yet, but we can still create simple objects if
desired:

use PlayingCard;
my $card = PlayingCard->new(); # works!

If you need your constructor to do more than just create an object with the
given attributes then Moose provides some handy construction hooks:
BUILDARGS and BUILD. To read more about these read
Moose::Manual::Construction.

Methods are just subroutines

Just as in regular OO Perl, we add subroutines to our class in order to
define object methods:

Read-write or read-only

When we declare an attribute we must specify whether whether
it is read-only (ro) or read-write (rw). Failing to do this
will not cause a warning, but will result in the attribute not being
usable which is a hard bug to track down. An attribute which is
read-only can only be set when the object is created, while attributes
which are read-write may have their value changed as required.

has 'suit' => (
# Suit is read-only
is => 'ro',
isa => 'Str',
);

In the case of our card, it doesn't make sense for a card to change either
its suit or its value after creation time. However, in a game
where cards can be face-up or face-down, it does make sense for
these to change:

Types

Moose provides a number of basic attribute types which we can use for our
class attributes. These form a simple hierarchy, where any more
specialised type may be used in the place of a more generalised type (for
example you can use an integer (Int) instead of a number (Num) and either
can be used where a string is expected. You can see this hierarchy by
reading perldoc Moose::Util::TypeConstraints and it is also reproduced
below:

Any type followed by a type parameter ['a] can be parameterised. Thus
you can write:

ArrayRef[Int] # an array of integers
HashRef[CodeRef] # a hash of str to CODE ref mappings
Maybe[Str] # value may be a string, may be undefined

You can also create your own types and constraints, which we will cover
later.

These are not a strong typing system for Perl 5. These are
constraints to ensure that attributes for Moose-based objects
contain what you expect them to.

Accessors

Once you have declared your attributes in your class, you automatically receive
accessor functions for them. These are named by the attribute name and if
your attribute is marked as read-write (rw) then you can use them to
change the value as well:

Moose will still check the type constraints and run any triggers with
methods named like this.

make_immutable

At the end of our PlayingCard class, above, we had the following line:

__PACKAGE__->meta->make_immutable;

Calling make_immutable makes Moose faster as your class' object
construction and destruction becomes inlined and no longer invokes the
meta API. It also declares that you do not intend to make any further changes
to the class via the metaclass API (which is what gives us all the cool Moose
features). This is why we do this at the end of our class declaration. In
essence this means that we cannot modify our class during the run-time of the
calling program, which is a rare thing to want to do, and thus a small price to
pay for the speed increase.

BUILDARGS and BUILD

For many objects, we would like to run code when an object is
created. This may be to attach to a resource, run validation checks,
or merely fill in some sensible defaults. Moose allows us to do
this by defining our own BUILDARGS and BUILD methods.

The BUILDARGS method, if defined, is executed before
the object is constructed. It's useful for tweaking our
arguments before they hit Moose. One very common use of
BUILDARGS is to support object construction with a non-hash
syntax. For example, we may allow our playing cards to be
constructed with a single argument (eg: 'Kh' for the king of hearts).

The BUILD method is called immediately after an object is
constructed. It's often useful to perform extra validation
steps, connect to a database, open a file, or otherwise do work
that needs to occur at object construction. For example, in the
game of Pontoon, tens are removed from the deck.

There is no need to call parental BUILD methods; in fact, it's
a grave mistake to do so. Moose ensures that all BUILD methods
are called. Parental BUILD methods are guaranteed to be called
before their children.