Sunday, January 29, 2012

Moose

Perl has been around for more than 20 years. During that time, it has received its share of both praise and criticism, and lots of misconceptions surround it. Much of this stems from long-outdated notions of what Perl used to be, but have nothing to do with what Perl actually is today.
Perl hasn't been standing still. It's been growing continuously and evolving, and that growth has accelerated dramatically in the past few years. Moose is one of the technologies at the heart of this "Perl Renaissance", which also includes other exciting projects that have emerged, such as Catalyst and DBIx::Class.
Moose is essentially a language extension for Perl 5 that provides a modern, elegant, fully featured object system. I say "language extension", but Moose is written in pure Perl, and as you'll see, its syntax is still normal Perl. You don't need to patch Perl itself to use Moose; under the hood, it's just Perl 5.
Because Moose is still just Perl 5, it's fully compatible with all of those wonderful modules on CPAN, regardless of whether they are written in Moose (and most aren't, as CPAN has been around for so long, and Moose is relatively new).
For me, this is still the single biggest reason to choose Perl. Whatever you are trying to accomplish, chances are, there already is a refined module for it on CPAN. This usually means dramatic cuts in total development time, because someone else already has written a lot of your program for you.
And now, with all the modern object-oriented features Moose brings to Perl, you get to have your cake and eat it too.
In this article, I provide an introduction to object-oriented programming in Moose and cover some of Moose's core features with useful examples. To get the most out of this article, you already should be familiar with object-oriented programming concepts, such as classes, objects, methods, attributes, construction and inheritance.
You also need to know Perl—at least the fundamentals. If you don't know Perl, learning it is not very hard to do. At the end of the day, it's just syntax. The good news is you don't need to master Perl by any stretch to start using Moose.
Perl does have its quirks, and Moose doesn't make them all totally go away (and you wouldn't want them all to go away, because a lot of them are really useful). The most important concepts to understand are how Perl references work (the "perlreftut" tutorial is a great place to start—see Resources), and also the basics of working with Scalars, Arrays and Hashes. Also, learn what the fat comma is (=>) if you aren't already familiar with it. Moose makes heavy use of it as an idiom. It's actually not that scary; it's interchangeable with the normal comma (,).
Most of the rest of it you can learn as you go. Normal language stuff like loops, conditionals and operators aren't all that different in Perl than any other language. So give it a shot. I think you'll find it's well worth the investment.

What about Perl 6?

A lot of the features in Moose were inspired by Perl 6. Perl 6 still is being developed actively, and I believe that when it's finally released for production use, it won't disappoint. The fact is Perl 5 is solid, proven and fast, so there is no reason to rush Perl 6. It is better that the developers take the time to do it really right, which is exactly what they're doing.

Getting Moose

Chances are you already have a distribution of Perl installed on your system. You at least should have Perl 5.8, but preferably 5.10 or 5.12. Installing Moose from CPAN is an easy task; simply run the following command:

cpan Moose
This should download and install Moose for you, as well as all of Moose's dependencies.

Object-Oriented Perl (the Old Way)

Even though Perl has had object-oriented features for a long time, it was not originally designed—syntactically—as an object-oriented language. This is more about the API provided to the programmer than it is about the underlying technical design of Perl itself.
Perl 5 provides a lean environment with the fundamental features and hooks needed for object-oriented programming, but then leaves most of the details (such as setting up object constructors, implementing attributes and handling validation) to you. As a result, the "right way" to go about implementing these concepts is open to interpretation.
The fundamental feature utilized by Perl to support objects is the "blessed" reference. This is like the flux capacitor of objects in Perl. Blessing simply associates a normal reference (usually a Hash reference) with a class. The blessed reference then becomes the "object instance", and its referent is used as the container to store the object's data.
The class name is the same thing as the package name, which is nothing more than the namespace in which subroutines and variables are defined. The subroutines defined in the given package namespace become the methods of the class and can be called on the object reference.
All object-oriented languages have to do something along these lines to implement objects under the hood. Other languages just don't impose so many of the low-level details on the programmer as in pure Perl.
Here is an example of a simple class in old-school Perl 5 OO:

package MyApp::Rifle;
use strict;

sub new {
        my ($class, %opts) = @_;
        $opts{rounds} = 0 unless ($opts{rounds});
        my $self = bless( {}, $class );
        $self->rounds($opts{rounds});
        return $self;
}

sub rounds {
        my ($self, $rounds) = @_;
        $self->{_rounds} = $rounds if (defined $rounds);
        return $self->{_rounds};
}

sub fire {
        my $self = shift;
        die "out of ammo!" unless ($self->rounds > 0);
        print "bang!\n";
        $self->rounds( $self->rounds - 1 );
}

1;
Save the above class definition into a file named MyApp/Rifle.pm within one of your Perl's include directories, and then you can use it in a Perl program like this:

use MyApp::Rifle;
use strict;

my $rifle = MyApp::Rifle->new( rounds => 5 );
print "There are " . $rifle->rounds . " rounds in the rifle\n";
$rifle->fire;
print "Now there are " . $rifle->rounds . " rounds in the rifle\n"; 
 
Further: http://www.linuxjournal.com/content/moose