Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Journal of Stevan (6065)

Thursday March 23, 2006
09:17 AM

Moose, it's the new Camel

[ #29081 ]

I have released a Moose onto CPAN :)

Moose is yet another way to write Perl 5 OO, however, this time it's different (it is, really, I swear). I have built Moose on top of the metaclass framework Class::MOP, so all the "magic" that Moose does is built upon the solid theoretical foundations found in other object systems like CLOS, Smalltalk 80 and SOM.

Moose development is still in the early stages, but since it is really just an interface to the underlying meta-objects of Class::MOP it is pretty stable. In fact, stability and lack of deep/dark magic are two key design goals of both Moose and Class::MOP, as well as the idea that you only pay for the features you use, and nothing else. Because Moose is built upon a metaclass framework, it is possible to encode a lot of information in a very small amout of code, and let the metaclasses do the bulk of the work. Here is an example taken from the tests:

package BankAccount;
use strict;
use warnings;
use Moose;

has 'balance' => (isa => 'Int', is => 'rw', default => 0);

sub deposit {
    my ($self, $amount) = @_;
    $self->balance($self->balance + $amount);
}

sub withdraw {
    my ($self, $amount) = @_;
    my $current_balance = $self->balance();
    ($current_balance >= $amount)
        || confess "Account overdrawn";
    $self->balance($current_balance - $amount);
}

package CheckingAccount;
use strict;
use warnings;
use Moose;

extends 'BankAccount';

has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');

before 'withdraw' => sub {
    my ($self, $amount) = @_;
    my $overdraft_amount = $amount - $self->balance();
    if ($overdraft_amount > 0) {
        $self->overdraft_account->withdraw($overdraft_amount);
        $self->deposit($overdraft_amount);
    }
};

The has keywords create instance attributes, with type constraints (isa => 'Int' etc), read/write accessors (is => 'rw') and "before" method wrappers allow for AOP style method "advice" which runs before the superclass method is called. But there is just as much that you don't see, such as; automatic inheritance from Moose::Object (where you inherit new and the Perl 6 style BUILD/BUILDALL constructor semantics), and full class introspection and reflection capabilities through the meta method.

Now, there are also a number of things which Moose is not. It is not another Inside-out object builder, it currently only supports blessed HASH based objects (surely the most common style), and possible future plans include adding support for blessed ARRAYs and such. But to be honest, one of the key ideas of Moose is to take away the need to worry about those types of things, and have everything Just Work, so that writing OO Perl code can be just as enjoyable as writing other Perl code.

Anyway, enough evangalism for now, please give Moose a try, I welcome any and all feedback (positive and negative), and feel free to come see us on #moose over at irc.perl.org.

-- Stevan

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Looks useful.

    However, the docs and synopsis need to cover "new" (if it is special somehow, how to define/redefine, if there is any support for default property values via named params (or not), how it looks on the using side, etc).
    • Yeah, lack of comprehensive docs are the biggest problem with Moose at this moment. I have been pondering a Moose::Cookbook for the next release, which should help. But for now, the first five tests are the best documentation (001-005)_basic.t.

      But to answer your questions ...

      • if it is special somehow

        Not "special" really, it just calls $self->meta->new_object(@_) to construct the instance, and the BUILDALL to run all the BUILD methods.

      • how to define/redefine

        The idea is that you dont have to def

  • Am i missing something or does the CheckingAccount fail to actualy withdraw money unless its more than is in the account?
    • The CheckingAccount::withdraw method is actually "before" method advice. It will run that sub before running the superclass code (BankAccount). So what happens is that if there is not enough money in the account to cover the withdrawl, it will withdraw money from an account designated as the "overdraft account" to compensate.

      The method "advice" feature, is something found in CLOS and some AOP systems. This example is actually taken directly from the book Practical Common Lisp [gigamonkeys.com] (scroll down to the section