Object Oriented Programming with Perl and Moose Dave Cross dave@perlschool.co.uk
6th April 2013 Perl School  Low cost Perl training  Training at all levels  Trying to build a buzz about Perl  Perl is not dead  Perl is Modern
6th April 2013 Xkcd Says
6th April 2013 Your Help Please  Trying to build a buzz about Perl  You can help  Please tell your friends  Blog  Twitter  Facebook  http://perlschool.co.uk
6th April 2013 Upcoming Courses  Perl School 6: Database Programming with Perl and DBIx::Class − 8th June 2013  http://perlschool.co.uk/upcoming/
6th April 2013 Timings  10:00 Session 1  11:15 Break  11:30 Session 2  13:00 Lunch  14:00 Session 3  15:30 Break  15:45 Session 4  17:00 End
6th April 2013 Admin Stuff  Tickets  Facilities  Lunch  Slides  Feedback
6th April 2013 8 What We Will Cover  Introduction to Object Oriented programming  Overview of Moose  Object Attributes  Subclasses  Object construction
6th April 2013 9 What We Will Cover  Data types  Delegation  Roles  Meta-programming  Alternatives to Moose  Further information
Object Oriented Programming
6th April 2013 11 What is OOP?  “Traditional” programming is procedural  Subroutines work on variables  my $twelve = regenerate($eleven);  Variables are dumb  Just stores for data
6th April 2013 12 What is OOP?  Object Oriented programming inverts this  Variables are objects  Objects can carry out certain processes − Called methods  my $twelve = $eleven->regenerate();  Objects are intelligent  Objects know what methods they can carry out
6th April 2013 13 Some Concepts  A Class is a type of intelligent variable − e.g. Time Lord  An Object is an instance of a class − e.g. The Doctor  A Method is an action that an object does − e.g. Regenerate  An Attribute is a piece of data in an object − e.g. Name
6th April 2013 14 Some Concepts  A class contains a number of methods  An object is of a particular class  The class defines the behaviour of an object  An object has many attributes − Data items  A class can also have attributes − Class-wide data items
6th April 2013 15 Methods  Methods can be either class methods or object methods  Class methods are called on a class − my $doctor = TimeLord->new;  Object methods are called on an object − $doctor->regenerate;
6th April 2013 16 Constructors  All classes need a constructor method  Creates a new object of that class  Usually a class method  Often called new  my $doctor = TimeLord->new;
6th April 2013 17 Constructors  A Class might have multiple constructors  my $doctor = TimeLord->new;  my $flesh_dr = TimeLord->clone($doctor);  A constructor might be an object method  my $flesh_dr = $doctor->clone;
6th April 2013 18 Accessors & Mutators  Access object attributes with an accessor method  say “The time lord's name is “, $doctor->get_name;  Change an attribute with a mutator method  $doctor->set_age( $doctor->get_age + 1 );
6th April 2013 19 Accessor/Mutators  Accessors and mutators are often the same method  say “The time lord's name is “, $doctor->name;  $doctor->age($doctor->age + 1);  Checks number of parameters  Reacts appropriately
6th April 2013 20 Accessor/Mutators  Which to choose?  Perl Best Practices says get_foo/set_foo  I like one method called foo  No firm rules  Pick one  Stick with it
6th April 2013 21 Subclasses  A subclass is a specialisation of a class  “Alien” is a class  “Dalek” is one possible subclass  Avoid reimplementing shared methods
6th April 2013 22 Subclasses  Subclasses alter behaviour of their parent classes  Add methods  Override existing methods  Add attributes  Override existing attributes
Object Oriented Perl
6th April 2013 24 OO Perl  Three rules of OO Perl  A class is a package  An object is reference  A method is a subroutine
6th April 2013 25 A Class is a Package  Same as any other package  Contains subroutines − Methods  Contains variables − Class attributes
6th April 2013 26 An Object is a Reference  Usually a reference to a hash  Hash keys are attribute names  Hash values are attribute values  Actually a “blessed” hash − So it knows what class it is
6th April 2013 27 A Method is a Subroutine  Just like any other subroutine  Some rules on parameters  First parameter is class name or object reference  Some differences in calling  Arrow notation − $doctor->name()
6th April 2013 28 Calling Methods  Methods are called using arrow notation  Class methods − TimeLord->new();  Object methods − $doctor->regenerate();
6th April 2013 29 Calling Methods  Perl rewrites the method call  Invocant passed as first argument  TimeLord->new();  TimeLord::new('Timelord');  $doctor->regenerate();  TimeLord::regenerate($doctor);
6th April 2013 30 Simple Class  package Alien; # package sub new { # subroutine my ($class, $name) = @_; # hash reference my $self = { name => $name }; return bless $self, $class; }
6th April 2013 31 Simple Class  sub name { # subroutine my ($self, $name) = @_; if (defined $name) { $self->{name} = $name; } return $self->{name}; # hash ref } 1;
6th April 2013 32 Using Our Class  use Alien; my $alien = Alien->new('Mork'); say $alien->name; # prints Mork $alien->name('Mork from Ork'); say $alien->name; # prints Mork from Ork
Moose
6th April 2013 34 Moose  Moose is a Modern Object System for Perl 5  Based on Perl 6 object system  More powerful  More flexible  Easier
6th April 2013 35 Simple Moose Class  package Alien; use Moose; has name => ( is => 'rw', isa => 'Str', ); no Moose; __PACKAGE__->meta->make_immutable;
6th April 2013 36 What's Going On?  use Moose;  Loads Moose environment  Makes our class a subclass of Moose::Object  Turns on use strict and use warnings
6th April 2013 37 Declarative Attributes  has name => ( is => 'rw', isa => 'Str', );  Creates an attribute called 'name'  Makes it read/write  Must be a string
6th April 2013 38 Read/Write Attributes  Moose creates methods to access/alter attributes  $alien->name('Strax'); say $alien->name;  The 'is' property controls how they work  'rw' : read and write  'ro' : read only
6th April 2013 39 Private Attributes  Use is => 'bare' for attributes that aren't readable  No methods are created  Direct hash access  $alien->{name} = 'Commander Strax';
6th April 2013 40 Other Methods  Not all methods are constructors or accessors/mutators  Write other methods as usual  First parameter is object reference
6th April 2013 41 Other Methods  package Timelord; ... sub regenerate { my $self = shift; my $curr = $self->regeneration; $self->regeneration(++$curr); }
6th April 2013 42 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
6th April 2013 43 Using Our Class  From the user's perspective, nothing changes  Use it just like other Perl classes  use Alien; my $strax = Alien->new( name => 'Strax' ); say $strax->name;  Named parameters are good
Subclasses
6th April 2013 Subclassing  A subclass is a specialisation of a superclass  More specific behaviour  New attributes  New methods  Overriding superclass methods and attributes
6th April 2013 Subclassing  Not all aliens are the same  package Dalek; use Moose; extends 'Alien'; has accuracy => ( isa => 'Num', is => 'rw', );
6th April 2013 Subclassing  sub exterminate { my $self = shift; say “EX-TERM-IN-ATE”; if (rand < $self->accuracy) { say “$_[0] has been exterminated”; return 1; } else { return; } }
6th April 2013 Using Subclasses  use Dalek; my $karn = Dalek->new( name => 'Karn', accuracy => 0.9, ); say $karn->name; $karn->exterminate('The Doctor');
6th April 2013 Overriding Methods  Daleks have a different way of using names  A Dalek's name is always “Dalek Something”  Need to override the name method from Alien  But we still want to get the name itself from Alien's method
6th April 2013 Method Modifiers  Moose has a declarative way to modify methods from your superclass  before : run this code before the superclass method  after : run this code after the superclass method  around : run this code around the superclass method
6th April 2013 Before and After  Methods defined with 'before' and 'after' are called before or after the parent's method  before name => sub { say 'About to call name()'; };  Doesn't interact with parent's method
6th April 2013 Around  Methods defined with 'around' are called instead of parent's method  It's your responsibility to call parent's method  Slightly different parameters − Original method name − Object reference − Any other parameters
6th April 2013 Dalek Names  around name => sub { my $orig = shift; my $self = shift; return 'Dalek ' . $self->$orig(@_); };
6th April 2013 Overriding Methods  Simpler way to override parent methods  override name => sub { my $self = shift; return 'Dalek ' . super(); };  Use the super keyword to call parent method  Passes on @_
Attributes
6th April 2013 Declarative Attributes  Attributes are declared in a class using the has keyword  This is different to “classic” Perl OO − Where attributes are created by the presence of accessor methods  Attributes have a number of properties  Properties define the attribute
6th April 2013 Properties  has name => ( isa => 'Str', is => 'rw', );  'isa' and 'is' are properties  Many other options exist
6th April 2013 is  is : defines whether you can read or write the attribute  Actually defines whether accessor method is created − And how it works  $obj->ro_attr('Some value');  “Cannot assign a value to a read-only accessor”
6th April 2013 Private Attributes  Use is => 'bare' for private attributes − No accessor created  Still get access through the object hash  has private => ( is => 'bare' );  $self->private; # Error  $self->{private};
6th April 2013 Accessor Name  “is” is actually a shortcut for two other properties  reader and writer  has name => ( reader => 'get_name', writer => 'set_name', );
6th April 2013 Accessor Name  Now we don't have a method called name  say $obj->name; # Error  Need to use get_name − say $obj->get_name;  And set_name − $obj->set_name('New Name');
6th April 2013 Best Practices  What is best practice − One method (name) − Two methods (get_name, set_name)  Who cares?  Choose one − And stick with it  Perl Best Practices says two methods − See MooseX::FollowPBP
6th April 2013 Required Attributes  By default Moose attributes are optional  Make them mandatory with required  has name => ( required => 1, );  my $alien = Alien->new;  “Attribute (name) is required at constructor Alien::new”
6th April 2013 Attribute Defaults  Set a default for missing attributes  has accuracy => ( default => 0.5, );  Or a subroutine reference  has accuracy => ( default => sub { rand }, );
6th April 2013 Attribute Builder  Define a builder method instead of a default subroutine  has accuracy => ( builder => '_build_accuracy', );  sub _build_accuracy { return rand; }  Easier to subclass
6th April 2013 Predicate  Define a method to check if an attribute has been set − Check for defined value  has name => ( isa => 'Str', predicate => 'has_name', );  No default
6th April 2013 Using Predicate  Use predicate method to check if an attribute is set  if ($random_alien->has_name) { say $random_alien->name; } else { say 'Anonymous Alien'; }
6th April 2013 Clearer  Define a method to clear an attribute − Sets to undef  has name => ( is => 'Str', clearer => 'clear_name', );  No default
6th April 2013 Using Clearer  Use clearer method to clear an attribute  if ($anon_alien->has_name) { $anon_alien->clear_name; }
6th April 2013 Attribute Types  Set the type of an attribute with isa  has accuracy => ( isa => 'Num', );  Validation checks run as value is set  We'll see more about types later
6th April 2013 Aggregate Attributes  You can define aggregate attributes  isa => 'ArrayRef' − Reference to array (elements are any type)  isa => 'ArrayRef[Int]' − Reference to array (elements are integers)
6th April 2013 Array Example  Daleks like to keep track of their victims  has victims ( is => 'rw', isa => 'ArrayRef[Str]', default => sub { [] }, );  And in the exterminate() method  push $self->victims, $_[0];
6th April 2013 Array Example  sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the Daleks'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Hash Attributes  Moose also supports hash ref attributes  has some_attribute => ( isa => 'HashRef[Str]', is => 'rw', );
6th April 2013 Easier Aggregates  Attribute traits can make it easier to use aggregate attributes  We will revisit this later
6th April 2013 76 Lazy Attributes  Some attributes are rarely used  And can be complex to construct  It's a waste of resources to build them before they are needed  Mark them as lazy  And define a build method
6th April 2013 77 Lazy Attributes  has useragent => ( is => 'LWP::UserAgent', lazy => 1, builder => '_build_ua', );  sub _build_ua { return LWP::UserAgent->new(...); }  $self->useragent->get(...); # creates object
6th April 2013 78 Triggers  A trigger is a subroutine that is called when an attribute's value changes  Subroutine is passed the old and new values  has name => ( trigger => &name_change, );  sub name_change { my ($self, $new, $old) = @_; warn “Name changed from $old to $new”; }
6th April 2013 79 Overriding Attributes  Subclasses can override attribute properties  Use '+' on the subclass attribute definition  has '+name' => ( ... );  Various properties can be changed − default, coerce, required, documentation, lazy, isa, handles, builder, metaclass, traits
6th April 2013 80 Sontaran Names  Many aliens don't have names  The 'name' attribute in Alien.pm doesn't have the 'required' property  Sontarans do use names  package Sontaran; has '+name' => ( required => 1, );
6th April 2013 More Types  Attributes can also be objects  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', );  Or a union of types  has output => ( is 'rw', isa => 'Object | Filehandle', );
6th April 2013 Attribute Delegation  Pass method calls to attributes − Assumes the attributes are objects  Defined using the 'handles' property  Defined with an array or hash reference
6th April 2013 Delegation with Array  Array contains list of method names  Named methods are passed through to attribute object  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', handles => [ qw( get post ) ], );
6th April 2013 Delegation with Array  $obj->get($url)  Is now equivalent to  $obj->useragent->get($url)
6th April 2013 Delegation with Hash  Allows renaming of methods  Hash contains key/values pairs of method names  Key is our object's method name  Value is the method name in the attribute object
6th April 2013 Delegation with Hash  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', handles => { get_data => 'get', post_data => 'post', }, );
6th April 2013 Delegation with Hash  $obj->get_data($url)  Is now equivalent to  $obj->useragent->get($url)
Constructors
6th April 2013 89 Constructors  A constructor is a special type of method  It is usually a class method  It returns a new object  Moose classes prefer named parameters  my $karn = Dalek->new( name => 'Karn', accuracy => 0.99, );
6th April 2013 90 Default Constructor  The default Moose constructor builds an object from its parameters  Checks for mandatory attributes  Checks type constraints  Returns an object
6th April 2013 91 Different Behaviour  Some constructors need to do other processing  Not just build an object  Sometimes it's convenient not to use named parameters  Use BUILD and BUILDARGS to override Moose's default behaviour
6th April 2013 92 BUILDARGS  More flexible parameters  Take a parameter list convert it to named parameters  Commonly Daleks only need a name  my $karn = Dalek->new( name => 'Karn' );  Why not simplify?  my $karn = Dalek->new('Karn');
6th April 2013 93 Dalek Construction  We can use BUILDARGS to build a list of named parameters  around BUILDARGS => sub { my $orig = shift; my $class = shift; if (@_ == 1 and !ref $_[0]) { return $class->$orig(name => $_[0]); } else { return $class->$orig(@_); } }
6th April 2013 94 Default BUILDARGS  We use 'around' to override BUILDARGS  Allows superclass BUILDARGS to be called  Moose has a default (top level) BUILDARGS  Converts named params to a hash ref − Alien->new(name => 'Mork') − Alien->new({name => 'Mork'})
6th April 2013 95 Announcing Your Dalek  When a new Dalek is created we want to announce its name  We can use the BUILD method  After a new object is constructed, the BUILD method is called  Use it to carry out any additional processing
6th April 2013 96 BUILD Example  sub BUILD { my $self = shift; say $self->name . ' is born.'; }  This method is called every time a new Dalek object is created  Called after the object is constructed  But before the new method returns
6th April 2013 97 Constructor Sequence  BUILDARGS called  Object constructed  BUILD called
Data Types
6th April 2013 Moose Data Types  Moose types are arranged in a hierarchy − Like class inheritance  Easy to add our own types  Easy to convert between types
6th April 2013 Type Hierarchy (Top)  Any  Item − Bool − Maybe[`a] − Undef − Defined  Value  Ref
6th April 2013 Type Hierarchy (Value)  Value − Str  Num − Int  ClassName  RoleName
6th April 2013 Type Hierarchy (Ref)  Ref − ScalarRef[`a] − ArrayRef[`a] − HashRef[`a] − CodeRef − RegexpRef − GlobRef  FileHandle − Object
6th April 2013 Parameterised Types  [`a] marks a parameter  Maybe[Str]  ScalarRef[Num]  ArrayRef[Int] − Array elements are integers  HashRef[Filehandle] − Hash values are filehandles
6th April 2013 Defining Types  You can define your own data types  Add constraints to existing types
6th April 2013 Defining Types  Remember that Daleks have an accuracy  Accuracy should be less than 1 − To give the Doctor a chance  Define your own type  subtype 'Accuracy' => as 'Num' => where { $_ < 1 };
6th April 2013 Using Types  has accuracy => ( isa => 'Accuracy', );  my $dalek = Dalek->new( accuracy => 1 );  “Attribute (accuracy) does not pass the type constraint because: Validation failed for 'Accuracy' with value 1 at constructor Dalek::new”
6th April 2013 Type Definition Tips  Name types within a project-specific namespace − PerlSchool::DrWho::Accuracy  See Moose::Types for utilities to make type definition easier
6th April 2013 Type Coercion  Convert between types  Automatically
6th April 2013 Dalek Birthdays  Daleks like to keep track of their creation date  They store it in a DateTime object  has creation ( is => 'ro', isa => 'DateTime', );
6th April 2013 Dalek Birthdays  It's hard to create a Dalek with a creation date  Dalek->new( name => "Karn", creation => "2013-04-06" )  “2013-04-06” is not a DateTime object
6th April 2013 Dalek Birthdays  Coerce a string into a DateTime  coerce 'DateTime' => from 'Str' => via { DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' )->parse_datetime($_) };  This doesn't work either
6th April 2013 Dalek Birthdays  Can't coerce into a standard type  Need to create a subtype  That's just how Moose works
6th April 2013 Dalek Birthdays  subtype 'Creation' as => 'DateTime'; coerce 'Creation' => from 'Str' => via { DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' )->parse_datetime($_) };
6th April 2013 Dalek Birthdays  has creation => ( isa => 'Creation', is => 'ro', coerce => 1, };  Dalek->new( name => "Karn", creation => "2013-04-06" );
Roles
6th April 2013 Inheritance  Inheritance is a useful feature of OO  Easy to create specialised subclasses  Easy to construct complex hierarchies of classes  Not so easy to maintain
6th April 2013 Multiple Inheritance  It's possible for one class to inherit from many superclasses  This can lead to “diamond inheritance” − Class D subclasses classes B and C − Classes B and C both subclass class A − What happens?  Complexity and confusion
6th April 2013 Roles  Roles address this issue  Cut-down classes that can be added into a class  Roles cannot be instantiated  A class “does” a role  Like interfaces or mixins
6th April 2013 Roles  Roles change the classes they are used by  Add methods  Add attributes  Enforce method definition
6th April 2013 Killer Aliens  Not all aliens are killers  Need a role for those who are  Force classes to implement a kill() method
6th April 2013 Killer Aliens  package Alien::Role::Killer; use Moose::Role; requires 'kill';  package Dalek; with 'Alien::Role::Killer';
6th April 2013 Killer Aliens  Now we can't use the Dalek class until we have defined a kill() method  perl -MDalek -E'Dalek->new(“Karn”)  'Alien::Killer' requires the method 'kill' to be implemented by 'Dalek'
6th April 2013 Killer Daleks  Let's cheat slightly  Rename exterminate() to kill()  Now we can use the Dalek class again
6th April 2013 Counting Victims  Remember how Daleks keep track of their victims?  That behaviour really belongs in the Alien::Role::Killer role  All killer aliens keep track of their victims  They just kill in different ways
6th April 2013 Counting Victims  The class shouldn't know about the role's attributes  Remember this line from exterminate() − push $self->victims, $_  How do we deal with that?  Use method modifiers
6th April 2013 Counting Victims  In Alien::Role::Killer  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
6th April 2013 Bragging About Victims  We also had a brag() method  Used the victims array  Move that into Alien::Role::Killer too
6th April 2013 Alien::Killer  package Alien::Role::Killer; use 5.010; use Moose::Role; requires 'kill'; has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, );
6th April 2013 Alien::Killer  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
6th April 2013 Alien::Killer  sub brag { my $self = shift; if (@{$self->victims}) { say $self->name . ' has killed ' . scalar @{$self->victims} . ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Alien::Killer  sub brag { my $self = shift; if (@{$self->victims}) { say $self->name . ' has killed ' . scalar @{$self->victims} . ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Dalek  package Dalek; use Moose; extends 'Alien'; with 'Alien::Role::Killer'; ...
6th April 2013 Killing People  #!/usr/bin/perl use strict; use warnings; use Dalek; my $d = Dalek->new("Karn"); foreach (1 .. 10) { $d->kill("Timelord $_"); } $d->brag;
6th April 2013 Killing People  $ ./killing.pl Dalek Karn is born. EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 2 has been exterminated EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 5 has been exterminated EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 9 has been exterminated EX-TERM-IN-ATE Timelord 10 has been exterminated Dalek Karn has killed 4 enemies of the Daleks Their names are: Timelord 2, Timelord 5, Timelord 9, Timelord 10
6th April 2013 Nicer Aggregate Attrs  We've seen aggregate attributes − Array or hash − victims is an example  We have to know that these are references − if (@{$self->victims}) − join ', ', @{self->victims} − push $self->victims, $victim # Perl 5.14  Can we make this easier?
6th April 2013 Nicer Aggregate Attrs  We can add traits to aggregate attribute definitions  Add simple methods to manipulate aggregate attributes  Hiding complexity
6th April 2013 New Properties  traits : Reference to a list of traits to add − Trait must match attribute type − ArrayRef / Array − HashRef / Hash − Etc.  handles : Maps new class methods onto trait methods
6th April 2013 Documentation  Moose::Meta::Trait::Native − List of types − High level examples  Moose::Meta::Attribute::Native::Trait::* − Full documentation of trait methods
6th April 2013 Types  Array  Bool  Code  Counter  Hash  Number  String
6th April 2013 Easier Victim Tracking  has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, traits => ['Array'], handles => { add_victim => 'push', all_victims => 'elements', count_victims => 'count', has_victims => 'count', }, );
6th April 2013 Easier Victim Tracking  has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, traits => ['Array'], handles => { add_victim => 'push', all_victims => 'elements', count_victims => 'count', has_victims => 'count', }, );
6th April 2013 Bragging (Before)  sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Bragging (Before)  sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Bragging (After)  sub brag { my $self = shift; if ($self->has_victims) { say $self->name . ' has killed ' . $self->count_victims, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', $self->all_victims); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Bragging (After)  sub brag { my $self = shift; if ($self->has_victims) { say $self->name . ' has killed ' . $self->count_victims, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', $self->all_victims); } else { say $self->name, ' has nothing to brag about'; } }
6th April 2013 Killing (Before)  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
6th April 2013 Killing (Before)  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
6th April 2013 Killing (After)  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { $self->add_victim($_[0]); } };
6th April 2013 Killing (After)  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { $self->add_victim($_[0]); } };
Meta Programming
6th April 2013 Meta Object Protocol  Moose is built on Class::MOP  A Meta Object Protocol  A set of classes that model a class framework  Class introspection
6th April 2013 The Meta Object  Access the MOP through your class's “meta” object  Get it through the meta() method − Class or object method  my $meta = Dalek->meta;
6th April 2013 Querying Classes  Class name  $meta->name  say Dalek->new->meta->name;  Superclasses  $meta->superclasses  @super = Dalek->new->meta->superclasses; say $super[0]->name; # Alien
6th April 2013 Querying Attributes  Get list of attributes  Each attribute is an object  foreach my $attr ( $meta->get_all_attributes ) { say $attr->name; say $attr->reader; say $attr->writer; }
6th April 2013 Querying Methods  Get a list of methods  Each method is an object  foreach my $meth ( $meta->get_all_methods ) { say $meth->name; say $meth->package_name; say $meth->body; }
6th April 2013 MOP is Read/Write  The MOP objects aren't read-only  You can change classes too − Until you call make_immutable  That's how Moose defines classes  See Class::MOP documentation
Moose Plugins
6th April 2013 Moose Plugins  Moose has a number of useful plugins  Many in the MooseX::* namespace − Important to pronounce that carefully  New ones added frequently  A survey of some of them
6th April 2013 Strict Constructors  Standard Moose ignores unknown constructor parameters  Dalek->new( name => 'Karn', email => 'karn@skaro.com', # huh? )  MooseX::StrictConstructor throws an error
6th April 2013 Parameter Validation  By default Perl is not strict about parameters to subroutines  Params::Validate is a useful CPAN module  MooseX::Params::Validate is a Moose wrapper
6th April 2013 Parameter Validation  package Foo; use Moose; use MooseX::Params::Validate; sub foo { my ( $self, %params ) = validated_hash( @_, bar => { isa => 'Str', default => 'Moose' }, ); return "Hooray for $params{bar}!"; }
6th April 2013 Singleton Object  A class that only ever has one instance  Highlander variable − “There can be only one”  MooseX::Singleton  use MooseX::Singleton;
6th April 2013 Nicer Class Definitions  In Moose a class is still a package  In Moose a method is still a subroutine  MooseX::Declare adds new keywords  Make your classes look more like classes  Make your methods look more like methods
6th April 2013 Nicer Class Definitions  class User { has 'name' => ( ... ); has 'email' => ( ... ); method login (Str $password) { ... } }  Still considered experimental  See also MooseX::Method::Signatures
6th April 2013 A Few More  MooseX::Types  MooseX::Types::Structures − Easier subtype definitions  MooseX::ClassAttributes
6th April 2013 A Few More  MooseX::Daemonize  MooseX::FollowPBP  MooseX::NonMoose − Moose subclasses of non-Moose classes
Alternatives to Moose
6th April 2013 Performance  Moose is relatively heavyweight  Adds a lot to your application  no moose and make_immutable both help  Moose team working on performance improvements  Lightweight alternatives
6th April 2013 Moo  “Minimalist Object Orientation (with Moose compatibility)”  Lightweight subset of Moose  Optimised for rapid start-up  No meta-object − Unless Moose is loaded  Support for roles
6th April 2013 Mo  Even smaller subset of Moose  new  has − All arguments are ignored  extends  Sometimes that is enough
6th April 2013 Mouse & Any::Moose  Mouse was an earlier light-weight Moose clone  Nowhere near as light-weight as Moo  Cut-down meta object  Any::Moose switches between Mouse and Moose  Moo is usually better Minimalist Object Orientation (with Moose compatiblity)
Further Information
6th April 2013 173 More Moose  Moose does a lot more  We have only scratched the surface  Good documentation − CPAN − Moose::Manual::* − Moose::Cookbook::*  No good book yet
6th April 2013 174 Help on Moose  Moose web site − http://moose.perl.org/  Mailing list − http://lists.perl.org/list/moose.html  IRC Channel − #moose on irc.perl.org
That's All Folks • Any Questions?

Object-Oriented Programming with Perl and Moose

  • 1.
    Object Oriented Programming with Perland Moose Dave Cross dave@perlschool.co.uk
  • 2.
    6th April 2013 Perl School Low cost Perl training  Training at all levels  Trying to build a buzz about Perl  Perl is not dead  Perl is Modern
  • 3.
  • 4.
    6th April 2013 Your HelpPlease  Trying to build a buzz about Perl  You can help  Please tell your friends  Blog  Twitter  Facebook  http://perlschool.co.uk
  • 5.
    6th April 2013 Upcoming Courses Perl School 6: Database Programming with Perl and DBIx::Class − 8th June 2013  http://perlschool.co.uk/upcoming/
  • 6.
    6th April 2013 Timings  10:00Session 1  11:15 Break  11:30 Session 2  13:00 Lunch  14:00 Session 3  15:30 Break  15:45 Session 4  17:00 End
  • 7.
    6th April 2013 Admin Stuff Tickets  Facilities  Lunch  Slides  Feedback
  • 8.
    6th April 2013 8 What WeWill Cover  Introduction to Object Oriented programming  Overview of Moose  Object Attributes  Subclasses  Object construction
  • 9.
    6th April 2013 9 What WeWill Cover  Data types  Delegation  Roles  Meta-programming  Alternatives to Moose  Further information
  • 10.
  • 11.
    6th April 2013 11 What isOOP?  “Traditional” programming is procedural  Subroutines work on variables  my $twelve = regenerate($eleven);  Variables are dumb  Just stores for data
  • 12.
    6th April 2013 12 What isOOP?  Object Oriented programming inverts this  Variables are objects  Objects can carry out certain processes − Called methods  my $twelve = $eleven->regenerate();  Objects are intelligent  Objects know what methods they can carry out
  • 13.
    6th April 2013 13 Some Concepts A Class is a type of intelligent variable − e.g. Time Lord  An Object is an instance of a class − e.g. The Doctor  A Method is an action that an object does − e.g. Regenerate  An Attribute is a piece of data in an object − e.g. Name
  • 14.
    6th April 2013 14 Some Concepts A class contains a number of methods  An object is of a particular class  The class defines the behaviour of an object  An object has many attributes − Data items  A class can also have attributes − Class-wide data items
  • 15.
    6th April 2013 15 Methods  Methodscan be either class methods or object methods  Class methods are called on a class − my $doctor = TimeLord->new;  Object methods are called on an object − $doctor->regenerate;
  • 16.
    6th April 2013 16 Constructors  Allclasses need a constructor method  Creates a new object of that class  Usually a class method  Often called new  my $doctor = TimeLord->new;
  • 17.
    6th April 2013 17 Constructors  AClass might have multiple constructors  my $doctor = TimeLord->new;  my $flesh_dr = TimeLord->clone($doctor);  A constructor might be an object method  my $flesh_dr = $doctor->clone;
  • 18.
    6th April 2013 18 Accessors &Mutators  Access object attributes with an accessor method  say “The time lord's name is “, $doctor->get_name;  Change an attribute with a mutator method  $doctor->set_age( $doctor->get_age + 1 );
  • 19.
    6th April 2013 19 Accessor/Mutators  Accessorsand mutators are often the same method  say “The time lord's name is “, $doctor->name;  $doctor->age($doctor->age + 1);  Checks number of parameters  Reacts appropriately
  • 20.
    6th April 2013 20 Accessor/Mutators  Whichto choose?  Perl Best Practices says get_foo/set_foo  I like one method called foo  No firm rules  Pick one  Stick with it
  • 21.
    6th April 2013 21 Subclasses  Asubclass is a specialisation of a class  “Alien” is a class  “Dalek” is one possible subclass  Avoid reimplementing shared methods
  • 22.
    6th April 2013 22 Subclasses  Subclassesalter behaviour of their parent classes  Add methods  Override existing methods  Add attributes  Override existing attributes
  • 23.
  • 24.
    6th April 2013 24 OO Perl Three rules of OO Perl  A class is a package  An object is reference  A method is a subroutine
  • 25.
    6th April 2013 25 A Classis a Package  Same as any other package  Contains subroutines − Methods  Contains variables − Class attributes
  • 26.
    6th April 2013 26 An Objectis a Reference  Usually a reference to a hash  Hash keys are attribute names  Hash values are attribute values  Actually a “blessed” hash − So it knows what class it is
  • 27.
    6th April 2013 27 A Methodis a Subroutine  Just like any other subroutine  Some rules on parameters  First parameter is class name or object reference  Some differences in calling  Arrow notation − $doctor->name()
  • 28.
    6th April 2013 28 Calling Methods Methods are called using arrow notation  Class methods − TimeLord->new();  Object methods − $doctor->regenerate();
  • 29.
    6th April 2013 29 Calling Methods Perl rewrites the method call  Invocant passed as first argument  TimeLord->new();  TimeLord::new('Timelord');  $doctor->regenerate();  TimeLord::regenerate($doctor);
  • 30.
    6th April 2013 30 Simple Class package Alien; # package sub new { # subroutine my ($class, $name) = @_; # hash reference my $self = { name => $name }; return bless $self, $class; }
  • 31.
    6th April 2013 31 Simple Class sub name { # subroutine my ($self, $name) = @_; if (defined $name) { $self->{name} = $name; } return $self->{name}; # hash ref } 1;
  • 32.
    6th April 2013 32 Using OurClass  use Alien; my $alien = Alien->new('Mork'); say $alien->name; # prints Mork $alien->name('Mork from Ork'); say $alien->name; # prints Mork from Ork
  • 33.
  • 34.
    6th April 2013 34 Moose  Mooseis a Modern Object System for Perl 5  Based on Perl 6 object system  More powerful  More flexible  Easier
  • 35.
    6th April 2013 35 Simple MooseClass  package Alien; use Moose; has name => ( is => 'rw', isa => 'Str', ); no Moose; __PACKAGE__->meta->make_immutable;
  • 36.
    6th April 2013 36 What's GoingOn?  use Moose;  Loads Moose environment  Makes our class a subclass of Moose::Object  Turns on use strict and use warnings
  • 37.
    6th April 2013 37 Declarative Attributes has name => ( is => 'rw', isa => 'Str', );  Creates an attribute called 'name'  Makes it read/write  Must be a string
  • 38.
    6th April 2013 38 Read/Write Attributes Moose creates methods to access/alter attributes  $alien->name('Strax'); say $alien->name;  The 'is' property controls how they work  'rw' : read and write  'ro' : read only
  • 39.
    6th April 2013 39 Private Attributes Use is => 'bare' for attributes that aren't readable  No methods are created  Direct hash access  $alien->{name} = 'Commander Strax';
  • 40.
    6th April 2013 40 Other Methods Not all methods are constructors or accessors/mutators  Write other methods as usual  First parameter is object reference
  • 41.
    6th April 2013 41 Other Methods package Timelord; ... sub regenerate { my $self = shift; my $curr = $self->regeneration; $self->regeneration(++$curr); }
  • 42.
    6th April 2013 42 Housekeeping  Mooseclasses 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
  • 43.
    6th April 2013 43 Using OurClass  From the user's perspective, nothing changes  Use it just like other Perl classes  use Alien; my $strax = Alien->new( name => 'Strax' ); say $strax->name;  Named parameters are good
  • 44.
  • 45.
    6th April 2013 Subclassing  Asubclass is a specialisation of a superclass  More specific behaviour  New attributes  New methods  Overriding superclass methods and attributes
  • 46.
    6th April 2013 Subclassing  Notall aliens are the same  package Dalek; use Moose; extends 'Alien'; has accuracy => ( isa => 'Num', is => 'rw', );
  • 47.
    6th April 2013 Subclassing  subexterminate { my $self = shift; say “EX-TERM-IN-ATE”; if (rand < $self->accuracy) { say “$_[0] has been exterminated”; return 1; } else { return; } }
  • 48.
    6th April 2013 Using Subclasses use Dalek; my $karn = Dalek->new( name => 'Karn', accuracy => 0.9, ); say $karn->name; $karn->exterminate('The Doctor');
  • 49.
    6th April 2013 Overriding Methods Daleks have a different way of using names  A Dalek's name is always “Dalek Something”  Need to override the name method from Alien  But we still want to get the name itself from Alien's method
  • 50.
    6th April 2013 Method Modifiers Moose has a declarative way to modify methods from your superclass  before : run this code before the superclass method  after : run this code after the superclass method  around : run this code around the superclass method
  • 51.
    6th April 2013 Before andAfter  Methods defined with 'before' and 'after' are called before or after the parent's method  before name => sub { say 'About to call name()'; };  Doesn't interact with parent's method
  • 52.
    6th April 2013 Around  Methodsdefined with 'around' are called instead of parent's method  It's your responsibility to call parent's method  Slightly different parameters − Original method name − Object reference − Any other parameters
  • 53.
    6th April 2013 Dalek Names around name => sub { my $orig = shift; my $self = shift; return 'Dalek ' . $self->$orig(@_); };
  • 54.
    6th April 2013 Overriding Methods Simpler way to override parent methods  override name => sub { my $self = shift; return 'Dalek ' . super(); };  Use the super keyword to call parent method  Passes on @_
  • 55.
  • 56.
    6th April 2013 Declarative Attributes Attributes are declared in a class using the has keyword  This is different to “classic” Perl OO − Where attributes are created by the presence of accessor methods  Attributes have a number of properties  Properties define the attribute
  • 57.
    6th April 2013 Properties  hasname => ( isa => 'Str', is => 'rw', );  'isa' and 'is' are properties  Many other options exist
  • 58.
    6th April 2013 is  is: defines whether you can read or write the attribute  Actually defines whether accessor method is created − And how it works  $obj->ro_attr('Some value');  “Cannot assign a value to a read-only accessor”
  • 59.
    6th April 2013 Private Attributes Use is => 'bare' for private attributes − No accessor created  Still get access through the object hash  has private => ( is => 'bare' );  $self->private; # Error  $self->{private};
  • 60.
    6th April 2013 Accessor Name “is” is actually a shortcut for two other properties  reader and writer  has name => ( reader => 'get_name', writer => 'set_name', );
  • 61.
    6th April 2013 Accessor Name Now we don't have a method called name  say $obj->name; # Error  Need to use get_name − say $obj->get_name;  And set_name − $obj->set_name('New Name');
  • 62.
    6th April 2013 Best Practices What is best practice − One method (name) − Two methods (get_name, set_name)  Who cares?  Choose one − And stick with it  Perl Best Practices says two methods − See MooseX::FollowPBP
  • 63.
    6th April 2013 Required Attributes By default Moose attributes are optional  Make them mandatory with required  has name => ( required => 1, );  my $alien = Alien->new;  “Attribute (name) is required at constructor Alien::new”
  • 64.
    6th April 2013 Attribute Defaults Set a default for missing attributes  has accuracy => ( default => 0.5, );  Or a subroutine reference  has accuracy => ( default => sub { rand }, );
  • 65.
    6th April 2013 Attribute Builder Define a builder method instead of a default subroutine  has accuracy => ( builder => '_build_accuracy', );  sub _build_accuracy { return rand; }  Easier to subclass
  • 66.
    6th April 2013 Predicate  Definea method to check if an attribute has been set − Check for defined value  has name => ( isa => 'Str', predicate => 'has_name', );  No default
  • 67.
    6th April 2013 Using Predicate Use predicate method to check if an attribute is set  if ($random_alien->has_name) { say $random_alien->name; } else { say 'Anonymous Alien'; }
  • 68.
    6th April 2013 Clearer  Definea method to clear an attribute − Sets to undef  has name => ( is => 'Str', clearer => 'clear_name', );  No default
  • 69.
    6th April 2013 Using Clearer Use clearer method to clear an attribute  if ($anon_alien->has_name) { $anon_alien->clear_name; }
  • 70.
    6th April 2013 Attribute Types Set the type of an attribute with isa  has accuracy => ( isa => 'Num', );  Validation checks run as value is set  We'll see more about types later
  • 71.
    6th April 2013 Aggregate Attributes You can define aggregate attributes  isa => 'ArrayRef' − Reference to array (elements are any type)  isa => 'ArrayRef[Int]' − Reference to array (elements are integers)
  • 72.
    6th April 2013 Array Example Daleks like to keep track of their victims  has victims ( is => 'rw', isa => 'ArrayRef[Str]', default => sub { [] }, );  And in the exterminate() method  push $self->victims, $_[0];
  • 73.
    6th April 2013 Array Example sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the Daleks'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
  • 74.
    6th April 2013 Hash Attributes Moose also supports hash ref attributes  has some_attribute => ( isa => 'HashRef[Str]', is => 'rw', );
  • 75.
    6th April 2013 Easier Aggregates Attribute traits can make it easier to use aggregate attributes  We will revisit this later
  • 76.
    6th April 2013 76 Lazy Attributes Some attributes are rarely used  And can be complex to construct  It's a waste of resources to build them before they are needed  Mark them as lazy  And define a build method
  • 77.
    6th April 2013 77 Lazy Attributes has useragent => ( is => 'LWP::UserAgent', lazy => 1, builder => '_build_ua', );  sub _build_ua { return LWP::UserAgent->new(...); }  $self->useragent->get(...); # creates object
  • 78.
    6th April 2013 78 Triggers  Atrigger is a subroutine that is called when an attribute's value changes  Subroutine is passed the old and new values  has name => ( trigger => &name_change, );  sub name_change { my ($self, $new, $old) = @_; warn “Name changed from $old to $new”; }
  • 79.
    6th April 2013 79 Overriding Attributes Subclasses can override attribute properties  Use '+' on the subclass attribute definition  has '+name' => ( ... );  Various properties can be changed − default, coerce, required, documentation, lazy, isa, handles, builder, metaclass, traits
  • 80.
    6th April 2013 80 Sontaran Names Many aliens don't have names  The 'name' attribute in Alien.pm doesn't have the 'required' property  Sontarans do use names  package Sontaran; has '+name' => ( required => 1, );
  • 81.
    6th April 2013 More Types Attributes can also be objects  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', );  Or a union of types  has output => ( is 'rw', isa => 'Object | Filehandle', );
  • 82.
    6th April 2013 Attribute Delegation Pass method calls to attributes − Assumes the attributes are objects  Defined using the 'handles' property  Defined with an array or hash reference
  • 83.
    6th April 2013 Delegation withArray  Array contains list of method names  Named methods are passed through to attribute object  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', handles => [ qw( get post ) ], );
  • 84.
    6th April 2013 Delegation withArray  $obj->get($url)  Is now equivalent to  $obj->useragent->get($url)
  • 85.
    6th April 2013 Delegation withHash  Allows renaming of methods  Hash contains key/values pairs of method names  Key is our object's method name  Value is the method name in the attribute object
  • 86.
    6th April 2013 Delegation withHash  has useragent => ( is => 'rw', isa => 'LWP::UserAgent', handles => { get_data => 'get', post_data => 'post', }, );
  • 87.
    6th April 2013 Delegation withHash  $obj->get_data($url)  Is now equivalent to  $obj->useragent->get($url)
  • 88.
  • 89.
    6th April 2013 89 Constructors  Aconstructor is a special type of method  It is usually a class method  It returns a new object  Moose classes prefer named parameters  my $karn = Dalek->new( name => 'Karn', accuracy => 0.99, );
  • 90.
    6th April 2013 90 Default Constructor The default Moose constructor builds an object from its parameters  Checks for mandatory attributes  Checks type constraints  Returns an object
  • 91.
    6th April 2013 91 Different Behaviour Some constructors need to do other processing  Not just build an object  Sometimes it's convenient not to use named parameters  Use BUILD and BUILDARGS to override Moose's default behaviour
  • 92.
    6th April 2013 92 BUILDARGS  Moreflexible parameters  Take a parameter list convert it to named parameters  Commonly Daleks only need a name  my $karn = Dalek->new( name => 'Karn' );  Why not simplify?  my $karn = Dalek->new('Karn');
  • 93.
    6th April 2013 93 Dalek Construction We can use BUILDARGS to build a list of named parameters  around BUILDARGS => sub { my $orig = shift; my $class = shift; if (@_ == 1 and !ref $_[0]) { return $class->$orig(name => $_[0]); } else { return $class->$orig(@_); } }
  • 94.
    6th April 2013 94 Default BUILDARGS We use 'around' to override BUILDARGS  Allows superclass BUILDARGS to be called  Moose has a default (top level) BUILDARGS  Converts named params to a hash ref − Alien->new(name => 'Mork') − Alien->new({name => 'Mork'})
  • 95.
    6th April 2013 95 Announcing YourDalek  When a new Dalek is created we want to announce its name  We can use the BUILD method  After a new object is constructed, the BUILD method is called  Use it to carry out any additional processing
  • 96.
    6th April 2013 96 BUILD Example sub BUILD { my $self = shift; say $self->name . ' is born.'; }  This method is called every time a new Dalek object is created  Called after the object is constructed  But before the new method returns
  • 97.
    6th April 2013 97 Constructor Sequence BUILDARGS called  Object constructed  BUILD called
  • 98.
  • 99.
    6th April 2013 Moose DataTypes  Moose types are arranged in a hierarchy − Like class inheritance  Easy to add our own types  Easy to convert between types
  • 100.
    6th April 2013 Type Hierarchy(Top)  Any  Item − Bool − Maybe[`a] − Undef − Defined  Value  Ref
  • 101.
    6th April 2013 Type Hierarchy(Value)  Value − Str  Num − Int  ClassName  RoleName
  • 102.
    6th April 2013 Type Hierarchy(Ref)  Ref − ScalarRef[`a] − ArrayRef[`a] − HashRef[`a] − CodeRef − RegexpRef − GlobRef  FileHandle − Object
  • 103.
    6th April 2013 Parameterised Types [`a] marks a parameter  Maybe[Str]  ScalarRef[Num]  ArrayRef[Int] − Array elements are integers  HashRef[Filehandle] − Hash values are filehandles
  • 104.
    6th April 2013 Defining Types You can define your own data types  Add constraints to existing types
  • 105.
    6th April 2013 Defining Types Remember that Daleks have an accuracy  Accuracy should be less than 1 − To give the Doctor a chance  Define your own type  subtype 'Accuracy' => as 'Num' => where { $_ < 1 };
  • 106.
    6th April 2013 Using Types has accuracy => ( isa => 'Accuracy', );  my $dalek = Dalek->new( accuracy => 1 );  “Attribute (accuracy) does not pass the type constraint because: Validation failed for 'Accuracy' with value 1 at constructor Dalek::new”
  • 107.
    6th April 2013 Type DefinitionTips  Name types within a project-specific namespace − PerlSchool::DrWho::Accuracy  See Moose::Types for utilities to make type definition easier
  • 108.
    6th April 2013 Type Coercion Convert between types  Automatically
  • 109.
    6th April 2013 Dalek Birthdays Daleks like to keep track of their creation date  They store it in a DateTime object  has creation ( is => 'ro', isa => 'DateTime', );
  • 110.
    6th April 2013 Dalek Birthdays It's hard to create a Dalek with a creation date  Dalek->new( name => "Karn", creation => "2013-04-06" )  “2013-04-06” is not a DateTime object
  • 111.
    6th April 2013 Dalek Birthdays Coerce a string into a DateTime  coerce 'DateTime' => from 'Str' => via { DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' )->parse_datetime($_) };  This doesn't work either
  • 112.
    6th April 2013 Dalek Birthdays Can't coerce into a standard type  Need to create a subtype  That's just how Moose works
  • 113.
    6th April 2013 Dalek Birthdays subtype 'Creation' as => 'DateTime'; coerce 'Creation' => from 'Str' => via { DateTime::Format::Strptime->new( pattern => '%Y-%m-%d' )->parse_datetime($_) };
  • 114.
    6th April 2013 Dalek Birthdays has creation => ( isa => 'Creation', is => 'ro', coerce => 1, };  Dalek->new( name => "Karn", creation => "2013-04-06" );
  • 115.
  • 116.
    6th April 2013 Inheritance  Inheritanceis a useful feature of OO  Easy to create specialised subclasses  Easy to construct complex hierarchies of classes  Not so easy to maintain
  • 117.
    6th April 2013 Multiple Inheritance It's possible for one class to inherit from many superclasses  This can lead to “diamond inheritance” − Class D subclasses classes B and C − Classes B and C both subclass class A − What happens?  Complexity and confusion
  • 118.
    6th April 2013 Roles  Rolesaddress this issue  Cut-down classes that can be added into a class  Roles cannot be instantiated  A class “does” a role  Like interfaces or mixins
  • 119.
    6th April 2013 Roles  Roleschange the classes they are used by  Add methods  Add attributes  Enforce method definition
  • 120.
    6th April 2013 Killer Aliens Not all aliens are killers  Need a role for those who are  Force classes to implement a kill() method
  • 121.
    6th April 2013 Killer Aliens package Alien::Role::Killer; use Moose::Role; requires 'kill';  package Dalek; with 'Alien::Role::Killer';
  • 122.
    6th April 2013 Killer Aliens Now we can't use the Dalek class until we have defined a kill() method  perl -MDalek -E'Dalek->new(“Karn”)  'Alien::Killer' requires the method 'kill' to be implemented by 'Dalek'
  • 123.
    6th April 2013 Killer Daleks Let's cheat slightly  Rename exterminate() to kill()  Now we can use the Dalek class again
  • 124.
    6th April 2013 Counting Victims Remember how Daleks keep track of their victims?  That behaviour really belongs in the Alien::Role::Killer role  All killer aliens keep track of their victims  They just kill in different ways
  • 125.
    6th April 2013 Counting Victims The class shouldn't know about the role's attributes  Remember this line from exterminate() − push $self->victims, $_  How do we deal with that?  Use method modifiers
  • 126.
    6th April 2013 Counting Victims In Alien::Role::Killer  around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
  • 127.
    6th April 2013 Bragging AboutVictims  We also had a brag() method  Used the victims array  Move that into Alien::Role::Killer too
  • 128.
    6th April 2013 Alien::Killer  packageAlien::Role::Killer; use 5.010; use Moose::Role; requires 'kill'; has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, );
  • 129.
    6th April 2013 Alien::Killer  aroundkill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
  • 130.
    6th April 2013 Alien::Killer  subbrag { my $self = shift; if (@{$self->victims}) { say $self->name . ' has killed ' . scalar @{$self->victims} . ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
  • 131.
    6th April 2013 Alien::Killer  subbrag { my $self = shift; if (@{$self->victims}) { say $self->name . ' has killed ' . scalar @{$self->victims} . ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
  • 132.
    6th April 2013 Dalek  packageDalek; use Moose; extends 'Alien'; with 'Alien::Role::Killer'; ...
  • 133.
    6th April 2013 Killing People #!/usr/bin/perl use strict; use warnings; use Dalek; my $d = Dalek->new("Karn"); foreach (1 .. 10) { $d->kill("Timelord $_"); } $d->brag;
  • 134.
    6th April 2013 Killing People $ ./killing.pl Dalek Karn is born. EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 2 has been exterminated EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 5 has been exterminated EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE EX-TERM-IN-ATE Timelord 9 has been exterminated EX-TERM-IN-ATE Timelord 10 has been exterminated Dalek Karn has killed 4 enemies of the Daleks Their names are: Timelord 2, Timelord 5, Timelord 9, Timelord 10
  • 135.
    6th April 2013 Nicer AggregateAttrs  We've seen aggregate attributes − Array or hash − victims is an example  We have to know that these are references − if (@{$self->victims}) − join ', ', @{self->victims} − push $self->victims, $victim # Perl 5.14  Can we make this easier?
  • 136.
    6th April 2013 Nicer AggregateAttrs  We can add traits to aggregate attribute definitions  Add simple methods to manipulate aggregate attributes  Hiding complexity
  • 137.
    6th April 2013 New Properties traits : Reference to a list of traits to add − Trait must match attribute type − ArrayRef / Array − HashRef / Hash − Etc.  handles : Maps new class methods onto trait methods
  • 138.
    6th April 2013 Documentation  Moose::Meta::Trait::Native −List of types − High level examples  Moose::Meta::Attribute::Native::Trait::* − Full documentation of trait methods
  • 139.
    6th April 2013 Types  Array Bool  Code  Counter  Hash  Number  String
  • 140.
    6th April 2013 Easier VictimTracking  has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, traits => ['Array'], handles => { add_victim => 'push', all_victims => 'elements', count_victims => 'count', has_victims => 'count', }, );
  • 141.
    6th April 2013 Easier VictimTracking  has victims => ( isa => 'ArrayRef[Str]', is => 'rw', default => sub { [] }, traits => ['Array'], handles => { add_victim => 'push', all_victims => 'elements', count_victims => 'count', has_victims => 'count', }, );
  • 142.
    6th April 2013 Bragging (Before) sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
  • 143.
    6th April 2013 Bragging (Before) sub brag { my $self = shift; if (@{$self->victims}) { say $self->name, ' has killed ', scalar @{$self->victims}, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', @{$self->victims}); } else { say $self->name, ' has nothing to brag about'; } }
  • 144.
    6th April 2013 Bragging (After) sub brag { my $self = shift; if ($self->has_victims) { say $self->name . ' has killed ' . $self->count_victims, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', $self->all_victims); } else { say $self->name, ' has nothing to brag about'; } }
  • 145.
    6th April 2013 Bragging (After) sub brag { my $self = shift; if ($self->has_victims) { say $self->name . ' has killed ' . $self->count_victims, ' enemies of the '.ref($self).'s'; say 'Their names are: ', join(', ', $self->all_victims); } else { say $self->name, ' has nothing to brag about'; } }
  • 146.
    6th April 2013 Killing (Before) around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
  • 147.
    6th April 2013 Killing (Before) around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { push $self->victims, $_[0]; } };
  • 148.
    6th April 2013 Killing (After) around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { $self->add_victim($_[0]); } };
  • 149.
    6th April 2013 Killing (After) around kill => sub { my $orig = shift; my $self = shift; if ($self->$orig(@_)) { $self->add_victim($_[0]); } };
  • 150.
  • 151.
    6th April 2013 Meta ObjectProtocol  Moose is built on Class::MOP  A Meta Object Protocol  A set of classes that model a class framework  Class introspection
  • 152.
    6th April 2013 The MetaObject  Access the MOP through your class's “meta” object  Get it through the meta() method − Class or object method  my $meta = Dalek->meta;
  • 153.
    6th April 2013 Querying Classes Class name  $meta->name  say Dalek->new->meta->name;  Superclasses  $meta->superclasses  @super = Dalek->new->meta->superclasses; say $super[0]->name; # Alien
  • 154.
    6th April 2013 Querying Attributes Get list of attributes  Each attribute is an object  foreach my $attr ( $meta->get_all_attributes ) { say $attr->name; say $attr->reader; say $attr->writer; }
  • 155.
    6th April 2013 Querying Methods Get a list of methods  Each method is an object  foreach my $meth ( $meta->get_all_methods ) { say $meth->name; say $meth->package_name; say $meth->body; }
  • 156.
    6th April 2013 MOP isRead/Write  The MOP objects aren't read-only  You can change classes too − Until you call make_immutable  That's how Moose defines classes  See Class::MOP documentation
  • 157.
  • 158.
    6th April 2013 Moose Plugins Moose has a number of useful plugins  Many in the MooseX::* namespace − Important to pronounce that carefully  New ones added frequently  A survey of some of them
  • 159.
    6th April 2013 Strict Constructors Standard Moose ignores unknown constructor parameters  Dalek->new( name => 'Karn', email => 'karn@skaro.com', # huh? )  MooseX::StrictConstructor throws an error
  • 160.
    6th April 2013 Parameter Validation By default Perl is not strict about parameters to subroutines  Params::Validate is a useful CPAN module  MooseX::Params::Validate is a Moose wrapper
  • 161.
    6th April 2013 Parameter Validation package Foo; use Moose; use MooseX::Params::Validate; sub foo { my ( $self, %params ) = validated_hash( @_, bar => { isa => 'Str', default => 'Moose' }, ); return "Hooray for $params{bar}!"; }
  • 162.
    6th April 2013 Singleton Object A class that only ever has one instance  Highlander variable − “There can be only one”  MooseX::Singleton  use MooseX::Singleton;
  • 163.
    6th April 2013 Nicer ClassDefinitions  In Moose a class is still a package  In Moose a method is still a subroutine  MooseX::Declare adds new keywords  Make your classes look more like classes  Make your methods look more like methods
  • 164.
    6th April 2013 Nicer ClassDefinitions  class User { has 'name' => ( ... ); has 'email' => ( ... ); method login (Str $password) { ... } }  Still considered experimental  See also MooseX::Method::Signatures
  • 165.
    6th April 2013 A FewMore  MooseX::Types  MooseX::Types::Structures − Easier subtype definitions  MooseX::ClassAttributes
  • 166.
    6th April 2013 A FewMore  MooseX::Daemonize  MooseX::FollowPBP  MooseX::NonMoose − Moose subclasses of non-Moose classes
  • 167.
  • 168.
    6th April 2013 Performance  Mooseis relatively heavyweight  Adds a lot to your application  no moose and make_immutable both help  Moose team working on performance improvements  Lightweight alternatives
  • 169.
    6th April 2013 Moo  “MinimalistObject Orientation (with Moose compatibility)”  Lightweight subset of Moose  Optimised for rapid start-up  No meta-object − Unless Moose is loaded  Support for roles
  • 170.
    6th April 2013 Mo  Evensmaller subset of Moose  new  has − All arguments are ignored  extends  Sometimes that is enough
  • 171.
    6th April 2013 Mouse &Any::Moose  Mouse was an earlier light-weight Moose clone  Nowhere near as light-weight as Moo  Cut-down meta object  Any::Moose switches between Mouse and Moose  Moo is usually better Minimalist Object Orientation (with Moose compatiblity)
  • 172.
  • 173.
    6th April 2013 173 More Moose Moose does a lot more  We have only scratched the surface  Good documentation − CPAN − Moose::Manual::* − Moose::Cookbook::*  No good book yet
  • 174.
    6th April 2013 174 Help onMoose  Moose web site − http://moose.perl.org/  Mailing list − http://lists.perl.org/list/moose.html  IRC Channel − #moose on irc.perl.org
  • 175.
    That's All Folks •Any Questions?