Moose: A Postmodern Object System for Perl Stuart Skelton
2 What is OOP? “Traditional” programming is procedural Subroutines work on variables my $distance = distance($point1,$point2); Variables are dumb Just stores for data
3 What is OOP? Object Oriented programming inverts this Variables are objects Objects can carry out certain processes Called methods my $distance = $point1- >distance($point2); Objects are intelligent Objects know what methods they can carry out
4 Some Concepts A Class is a type of intelligent variable (blueprint of an object) e.g. Dog An Object is an instance of a class e.g. Amber An Attribute is a piece of data in an object e.g. KennelClubName A Method is an action that an object does e.g. Bark
5 Methods M ethods can be either class methods or object methods Class methods are called on a class my $amber = Dog->new; Object methods are called on an object $amber->bark;
6 Constructors All classes need a constructor method Creates a new object of that class Usually a class method Often called new my $amber = Dog->new; my $hunter = new Dog;
7 Accessors & Mutators Access object attributes with an accessor method say “The kennel club name of Amber is “,$amber->get_kennel_club_name; Change an attribute with a mutator method $amber->set_age( $amber->get_age + 1 );
8 Accessor & Mutators Accessors and mutators are often the same method say “The kennel club name of Amber is “, $amber->kennel_club_name; $amber->age($amber->age + 1); Checks number of parameters Reacts appropriately
9 Traditional Perl OOP
10 Basic Anatomy Package Classname; atribute1 attribute2 method1 method2 1;
package PointTP; sub new { my $class = shift; my $self = { x => shift, y => shift, }; bless $self, $class; return $self; } sub set_x { my ( $self, $x ) $self->{x} = $x if defined($x); } sub get_x { my( $self ) return $self->{x}; } sub set_y { my ( $self, $y ) $self->{y} = $y if defined($y); } sub get_y { my( $self ) return $self->{y}; }
#!/usr/bin/perl use Modern::Perl ; use PointTP ; my $point1 = Point->new(1,2) ; say $point1->get_x() ; # prints 1 #change the x-coord $point1->set_x(-10); say $point1->get_x() ; # prints -10
sub set_x { my ( $self, $x ) $self->{x} = $x if defined($x); } sub get_x { my( $self ) return $self->{x}; } sub x { my ($self, $new_x) if (defined $new_x) { $self->{x} = $new_x; } return $self->{x}; }
#!/usr/bin/perl use Modern::Perl ; use Point ; my $point1 = Point->new(1,2) ; say $point1->x() ; # prints 1 #change the x-coord $point1->x(-10); say $point1->x() ; # prints -10
Moose
16 Moose Moose is a Modern Object System for Perl 5 Based on Perl 6 object system More powerful More flexible Easier
17 Simple Moose Class package Point; use Moose; has x => ( is => 'rw', isa => 'Num', required => 1 ); has y => ( is => 'rw', isa => 'Num', required => 1 ); no Moose; __PACKAGE__->meta->make_immutable;
18 What's Going On? use Moose; Loads Moose environment Makes our class a subclass of Moose::Object Turns on use strict and use warnings
19 Declarative Attributes has x => ( is => 'rw', isa => 'Num', required => 1 ); Creates an attribute called 'x' Makes it read/write Must be a number Is required
20 Housekeeping Moose classes carry a lot of baggage We can (and should) turn some of it off no Moose; Remove Moose exports from your namespace See also namespace::autoclean __PACKAGE__->meta->make_immutable; No more changes to class definition Performance improvements
Required Attributes By default Moose attributes are optional Make them mandatory with required has x => (... required => 1, ); my $point1 = Point->new; “Attribute (x) is required at constructor Point::new”
Attribute Defaults Set a default for missing attributes has accuracy => ( default => 0.5, ); Or a subroutine reference has accuracy => ( default => sub { rand }, );
Attribute Builder Define a builder method instead of a default subroutine has accuracy => ( builder => '_build_accuracy', ); sub _build_accuracy { return rand; } Easier to subclass
24 Read/Write Attributes Moose creates methods to access/alter attributes $point1->x(-1); say $point1->x; The 'is' property controls how they work 'rw' : read and write 'ro' : read only
25 Read/Write Attributes But PBP says use get_* and set_* has x => (...., reader => get_x, Writer => set_x, ); use MooseX::FollowPBP; Rule of Thumb, pick a style and stick with it
26 Other Methods Not all methods are constructors or accessors/mutators Write other methods as usual First parameter is object reference
27 Other Methods package Point;... sub distance { my $self = shift ; my $newpoint = shift ; return unless $newpoint->isa('Point') ; return sqrt( ($self->x - $newpoint- >x)**2 + ($self->y - $newpoint- >y)**2 ) ; }
28 Using the Point #!/usr/bin/perl use Modern::Perl ; use Point ; my $point1 = Point->new(x=>-7,y=>- 4) ; my $point2 = Point->new(x=>17,y=>6) ; say join ' ', 'The Distance between point 1', $point1->toString, 'and point 2', $point2->toString, 'is', $point1- >distance($point2) ; # prints 'The Distance between point 1 (-7,-4) and point 2 (17,6) is 26'
Sub Classing A subclass is a specialisation of a superclass More specific behaviour New attributes New methods Overriding superclass methods and attributes
30 package Point3D; use Moose; extends 'Point' ; has z => ( is => 'rw', isa => 'Num', required => 1 ); override distance => sub { my $self = shift; my $newpoint = shift; return unless $newpoint->isa('Point3D') ; my $distance2d = super(); return sqrt( $distance2d**2 + ($self->z - $newpoint->z)**2 ) ; };
31 use Modern::Perl ; use Point3D ; my $point1 = Point3D->new(x=>-7,y=>-4,z=>3); my $point2 = Point3D->new(x=>17,y=>6,z=>2.5); say join ' ', 'The Distance between point 1', $point1->toString, 'and point 2', $point2->toString, 'is', $point1->distance($point2) ; # prints 'The Distance between point 1 (-7,- 4,3) and point 2 (17,6,2.5) is '
32 Other Atrribute types any Item Bool Maybe[`a] Undef Defined Value Str Num Int ClassName RoleName Ref ScalarRef[`a] ArrayRef[`a] HashRef[`a] CodeRef RegexpRef GlobRef FileHandle Object
33 package Farm; use Moose; has 'animals' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[Animal]', default => sub { [] }, handles => { all_animals => 'elements', add_animal => 'push', find_animal => 'first', get_animal => 'get', count_animals => 'count', has_animals => 'count', has_no_animals => 'is_empty', sorted_animals => 'sort', }, ); no Moose; 1;
34 package Galaxy; use Moose; has 'planets' => ( traits => ['Hash'], is => 'ro', isa => 'HashRef[Planets]', default => sub { {} }, handles => { set_planets => 'set', get_planets => 'get', has_no_planets => 'is_empty', num_planets => 'count', delete_planets => 'delete', }, ); no Moose; 1;
35 Further Information Moose does a lot more We have only scratched the surface Good documentation CPAN Moose::Manual::* Moose::Cookbook::* No good book yet