NAME¶
Moose::Cookbook::Basics::Point_AttributesAndSubclassing - Point and Point3D
classes, showing basic attributes and subclassing.
VERSION¶
version 2.1213
SYNOPSIS¶
package Point;
use Moose;
has 'x' => (isa => 'Int', is => 'rw', required => 1);
has 'y' => (isa => 'Int', is => 'rw', required => 1);
sub clear {
my $self = shift;
$self->x(0);
$self->y(0);
}
package Point3D;
use Moose;
extends 'Point';
has 'z' => (isa => 'Int', is => 'rw', required => 1);
after 'clear' => sub {
my $self = shift;
$self->z(0);
};
package main;
# hash or hashrefs are ok for the constructor
my $point1 = Point->new(x => 5, y => 7);
my $point2 = Point->new({x => 5, y => 7});
my $point3d = Point3D->new(x => 5, y => 42, z => -5);
DESCRIPTION¶
This is the classic Point example. It is taken directly from the Perl 6
Apocalypse 12 document, and is similar to the example found in the classic
K&R C book as well.
As with all Perl 5 classes, a Moose class is defined in a package. Moose handles
turning on "strict" and "warnings" for us, so all we need
to do is say "use Moose", and no kittens will die.
When Moose is loaded, it exports a set of sugar functions into our package. This
means that we import some functions which serve as Moose "keywords".
These aren't real language keywords, they're just Perl functions exported into
our package.
Moose automatically makes our package a subclass of Moose::Object. The
Moose::Object class provides us with a constructor that respects our
attributes, as well other features. See Moose::Object for details.
Now, onto the keywords. The first one we see here is "has", which
defines an instance attribute in our class:
has 'x' => (isa => 'Int', is => 'rw', required => 1);
This will create an attribute named "x". The "isa" parameter
says that we expect the value stored in this attribute to pass the type
constraint for "Int" (1). The accessor generated for this attribute
will be read-write.
The "required => 1" parameter means that this attribute must be
provided when a new object is created. A point object without coordinates
doesn't make much sense, so we don't allow it.
We have defined our attributes; next we define our methods. In Moose, as with
regular Perl 5 OO, a method is just a subroutine defined within the package:
sub clear {
my $self = shift;
$self->x(0);
$self->y(0);
}
That concludes the
Point class.
Next we have a subclass of
Point,
Point3D. To declare our
superclass, we use the Moose keyword "extends":
extends 'Point';
The "extends" keyword works much like "use base"/"use
parent". First, it will attempt to load your class if needed. However,
unlike "base", the "extends" keyword will
overwrite
any previous values in your package's @ISA, where "use base" will
"push" values onto the package's @ISA.
It is my opinion that the behavior of "extends" is more intuitive.
(2).
Next we create a new attribute for
Point3D called "z".
has 'z' => (isa => 'Int', is => 'rw', required => 1);
This attribute is just like
Point's "x" and "y"
attributes.
The "after" keyword demonstrates a Moose feature called "method
modifiers" (or "advice" for the AOP inclined):
after 'clear' => sub {
my $self = shift;
$self->z(0);
};
When "clear" is called on a
Point3D object, our modifier method
gets called as well. Unsurprisingly, the modifier is called
after the
real method.
In this case, the real "clear" method is inherited from
Point.
Our modifier method receives the same arguments as those passed to the
modified method (just $self here).
Of course, using the "after" modifier is not the only way to
accomplish this. This
is Perl, right? You can get the same results with
this code:
sub clear {
my $self = shift;
$self->SUPER::clear();
$self->z(0);
}
You could also use another Moose method modifier, "override":
override 'clear' => sub {
my $self = shift;
super();
$self->z(0);
};
The "override" modifier allows you to use the "super"
keyword to dispatch to the superclass's method in a very Ruby-ish style.
The choice of whether to use a method modifier, and which one to use, is often a
question of style as much as functionality.
Since
Point inherits from Moose::Object, it will also inherit the default
Moose::Object constructor:
my $point1 = Point->new(x => 5, y => 7);
my $point2 = Point->new({x => 5, y => 7});
my $point3d = Point3D->new(x => 5, y => 42, z => -5);
The "new" constructor accepts a named argument pair for each attribute
defined by the class, which you can provide as a hash or hash reference. In
this particular example, the attributes are required, and calling
"new" without them will throw an error.
my $point = Point->new( x => 5 ); # no y, kaboom!
From here on, we can use $point and $point3d just as you would any other Perl 5
object. For a more detailed example of what can be done, you can refer to the
t/recipes/moose_cookbook_basics_point_attributesandsubclassing.t test
file.
Moose Objects are Just Hashrefs¶
While this all may appear rather magical, it's important to realize that Moose
objects are just hash references under the hood (3). For example, you could
pass $self to "Data::Dumper" and you'd get exactly what you'd
expect.
You could even poke around inside the object's data structure, but that is
strongly discouraged.
The fact that Moose objects are hashrefs means it is easy to use Moose to extend
non-Moose classes, as long as they too are hash references. If you want to
extend a non-hashref class, check out "MooseX::InsideOut".
CONCLUSION¶
This recipe demonstrates some basic Moose concepts, attributes, subclassing, and
a simple method modifier.
- (1)
- Moose provides a number of builtin type constraints, of which
"Int" is one. For more information on the type constraint
system, see Moose::Util::TypeConstraints.
- (2)
- The "extends" keyword supports multiple inheritance. Simply pass
all of your superclasses to "extends" as a list:
extends 'Foo', 'Bar', 'Baz';
- (3)
- Moose supports using instance structures other than blessed hash
references (such as glob references - see MooseX::GlobRef).
SEE ALSO¶
- Method Modifiers
- The concept of method modifiers is directly ripped off from CLOS. A great
explanation of them can be found by following this link.
<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>
AUTHORS¶
- •
- Stevan Little <stevan.little@iinteractive.com>
- •
- Dave Rolsky <autarch@urth.org>
- •
- Jesse Luehrs <doy@tozt.net>
- •
- Shawn M Moore <code@sartak.org>
- •
- XXXX XXX'XX (Yuval Kogman) <nothingmuch@woobling.org>
- •
- Karen Etheridge <ether@cpan.org>
- •
- Florian Ragwitz <rafl@debian.org>
- •
- Hans Dieter Pearcey <hdp@weftsoar.net>
- •
- Chris Prather <chris@prather.org>
- •
- Matt S Trout <mst@shadowcat.co.uk>
COPYRIGHT AND LICENSE¶
This software is copyright (c) 2006 by Infinity Interactive, Inc..
This is free software; you can redistribute it and/or modify it under the same
terms as the Perl 5 programming language system itself.