Programming with Moose/Problems solved/Accessors

Perl has two aggregate (non-scalar) data types: arrays and hashes (i.e., associative arrays) which are commonly used as the base data structure for objects. A more serious problem is that neither of these data types is an object. For instance, native array and hash support doesn't allow you to receive an event trigger when you write a new key-value pair to a hash, or when you push a new element onto an array. It's possible to use Perl's tie() mechanism to get this, but tie() comes with a serious performance penalty. Perl does enhance the C-style array of fixed size - a simple contiguous block of memory, addressed via indexing - to allow it to grow or shrink as needed, but chose for reasons of efficiency to implement only basic operations.[1]

One of the two might be better for one task, and not applicable for another, but that doesn't matter. With Moose, your program isn't directly tied to a Perl data structure.

The old way

edit

Traditionally, Class::Accessor, has done the most for arena, we'll see that soon. The problem it solved was a big and simple one, and it didn't overachieve one bit: if you've got a hash and you don't want a key: foobar to be inserted, how do you go about it? You simply bless the hash into an object and say what accessors should be generated. Now this "hash" acts as watered down model that your module can wrap to achieve the goals of the program. When an unrelated function is called perl realizes it can't resolve the method to a matching sub and errors.[2]

An Example

edit

Examine the terseness of this code.

package OldWay;
use strict;
use warnings;

use base 'Class::Accessor'; ## or C::A::Fast, or C::A::More, et al.

BEGIN { Class::Accessor->mk_accessors( qw/ foo bar baz / ) }

sub new {
	my $class = shift;
	bless {}, $class;
}

package main;
use strict;
use warnings;

my $obj = OldWay->new;

## These work
$obj->foo( 1 );
$obj->bar( OldWay->new );
$obj->baz( 'foo' );

## Anything else will die
$obj->quz( 1 ); #die

Here we create an object, essentially a hash that permits only three keys. The getters and setters for this hash directly correlate to the keys in the underlying perl hash. Remember, that a Perl object is very simple. complexities are left as an exercise to the programmer.

Invoking the Moose

edit

Truth be told, Moose is more than a replacement for Class::Accessor. So, off the shelf, it won't compete with the simplicity of Class::Accessor. In this section however, we will see Moose's analog.[3]

An Example

edit
package NewWay;
use Moose;

has 'foo' => ( isa  => 'Value', is => 'rw' );
has 'bar' => ( isa  => 'Value', is => 'rw' );
has 'baz' => ( isa  => 'Value', is => 'rw' );
# or just
# has [qw/ foo bar baz /] => ( isa  => 'Value', is => 'rw' );

package main;
use strict;
use warnings;

my $obj = NewWay->new;

## Rest of the module is the same..

## These work
$obj->foo( 1 );
$obj->bar( NewWay->new );
$obj->baz( 'foo' );

## Anything else will die
$obj->quz( 1 ); #die

Pretty simple. No syntax thus far really needs explaining -- but in the next section we will anyway.

New Syntax

edit

For clarity and those who just can't learn by example:

has is one of few Moose keywords, it begins a Moose expression that declares a statement.

See also: has

isa in the context of has refers to the TypeConstraint of the object. Moose has a built in type system, and this keyword, which will be explained further in the next chapter specifies what values this attribute is to accept.

See also: has

is in the context of has refers to the type of accessors to be created. A value of rw will instruct Moose to forge a setter and getter, while a value of ro will only yield a get'er.

Footnotes

edit
  1. ^ Unless of course you have explicitly crafted a sub AUTOLOAD {}, let's not be bothered with this exception though.
  2. ^ By fixed we mean you can push onto both sides of the array. There is no guarantee new data will be contiguous to the old data. When you program with perl you aren't supposed to think at a low level, don't worry about what happens just know it'll work.
  3. ^ Of course, with Moose::Tiny you will probably get a more powerful and more terse alternative to Class::Accessor but we will address MooseX:: and alternatives at a later point in this book.