Even for a curmudgeon like me who doesn’t make much use of object orientation, Moose offers something which supports my programming with types style: a degree of run-time type checking and the ability to create a range of convenience functions with very little code.
Say I have a person who makes a bunch of orders consisting of a bunch of items. My hashref might look something like this:
my $data = { fred => { orders => [ { order_id => 'fred1', items => [ { description => 'roses' }, ], }, { order_id => 'fred1', items => [ { description => 'one true ring' }, ], }, ], }, };
Then I’ll probably need a bunch of convenience functions to make sure I’m adding items to orders rather than people.
In Moose, including the type checking, that looks like:
Item
package Item; use Moose; has description => ( is => 'ro', isa => 'Str', ); no Moose; __PACKAGE__->meta->make_immutable;
Order
package Order; use Moose; has order_id => ( is => 'ro', isa => 'Str', required => 1, ); has items => ( is => 'rw', isa => 'ArrayRef[Item]', default => sub { [] }, traits => ['Array'], handles => { add_item => 'push', get_items => 'elements', }, ); no Moose; __PACKAGE__->meta->make_immutable;
Person
package Person; use Moose; has name => ( is => 'ro', isa => 'Str', required => 1, ); has orders => is => 'rw', isa => 'ArrayRef[Order]', default => sub { [] }, traits => ['Array'], handles => { add_order => 'push', get_orders => 'elements', }, no Moose; __PACKAGE__->meta->make_immutable;
Adding an item as an order gives a nice error message:
my $fred = Person->new(name => 'fred'); my $item = Item->new(description => 'One true ring'); $fred->add_order($item);
$ perl moose-arrays.pl A new member value for orders does not pass its type constraint because:
Validation failed for 'Order' with value Item=HASH(0x9ad3ec8)
(not isa Order) at moose-arrays.pl line 63
Moose ensures you pass an order to add_order(…).
my $order1 = Order->new(order_id => 'fred1'); my $item = Item->new(description => 'One true ring'); $order1->add_item($item); $fred->add_order($order1); my $order2 = Order->new(order_id => 'fred2'); $fred->add_order($order2); use Data::Dumper; print Dumper($fred);
$VAR1 = bless( { 'orders' => [ bless( { 'order_id' => 'fred1', 'items' => [ bless( { 'description' => 'One true ring' }, 'Item' ) ] }, 'Order' ), bless( { 'order_id' => 'fred2', 'items' => [] }, 'Order' ) ], 'name' => 'fred' }, 'Person' );
I like it when someone else has already written the code I would otherwise need to write myself.