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
editTraditionally, 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
editExamine 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
editTruth 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
editpackage 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
editFor clarity and those who just can't learn by example:
has
edithas is one of few Moose keywords, it begins a Moose expression that declares a statement.
isa
editisa 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.
is
editis 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- ^ Unless of course you have explicitly crafted a
sub AUTOLOAD {}
, let's not be bothered with this exception though. - ^ 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.
- ^ Of course, with
Moose::Tiny
you will probably get a more powerful and more terse alternative toClass::Accessor
but we will addressMooseX::
and alternatives at a later point in this book.