Moose, it's the new Camel

Stevan on 2006-03-23T14:17:20

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


Docs

jplindstrom on 2006-03-23T15:41:06

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).

Re:Docs

Stevan on 2006-03-23T17:13:24

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 define it, a sane default is provided for you and will handle 80% of your needs. If you redefine it, I suggest calling SUPER::new.
  • if there is any support for default property values via named params (or not)
    Yes, this is how the default one works, it will only store params if they are a valid slot value though, it will just ignore other values (you can fiddle with them in BUILD if you want though)
  • how it looks on the using side
    Basically like this: Foo->new(bar => 'baz').
For the most part it works as &new will work in Perl 6.

-- Stevan

Your inherited class

eric256 on 2006-03-23T22:12:04

Am i missing something or does the CheckingAccount fail to actualy withdraw money unless its more than is in the account?

Re:Your inherited class

Stevan on 2006-03-23T23:06:49

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 (scroll down to the section entitled "The Standard Method Combination" to see). Moose also supports the other "method combinations" from CLOS too (after, around). In fact you can see an example of after is the Moose SYNOPSIS.

-- Stevan

Re:Your inherited class

eric256 on 2006-03-27T16:54:06

Thanks....I totaly spaced on the "before". Pretty cool.