350 likes | 460 Views
Moose: A Postmodern Object System for Perl Stuart Skelton. What is OOP?. “Traditional” programming is procedural Subroutines work on variables my $distance = distance($point1,$point2); Variables are dumb Just stores for data. What is OOP?. Object Oriented programming inverts this
E N D
Moose: A Postmodern Object System for Perl Stuart Skelton
What is OOP? “Traditional” programming is procedural Subroutines work on variables my $distance = distance($point1,$point2); Variables are dumb Just stores for data
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
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
Methods Methods 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;
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;
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);
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
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 Moose is a Modern Object System for Perl 5 Based on Perl 6 object system More powerful More flexible Easier
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;
What's Going On? use Moose; Loads Moose environment Makes our class a subclass of Moose::Object Turns on use strict and use warnings
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
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
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
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
Other Methods Not all methods are constructors or accessors/mutators Write other methods as usual First parameter is object reference
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 ) ; }
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
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 ) ; };
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 26.0048072478917'
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
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;
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;
Further Information Moose does a lot more We have only scratched the surface Good documentation CPAN Moose::Manual::* Moose::Cookbook::* No good book yet