Programming with Moose/Problems solved
Perl (prior to version 5.10) has an illogical Method Resolution Order (MRO), this becomes apparent when using multiple inheritance dispatching. A fix for MI-dispatching was first popularized with Dameon's NEXT
, which turned out to be a buggy hack that failed horribly in many cases. NEXT
was unfortunately inducted into the CORE distro with Perl v5.7.3 and remains in the CORE even today. Moose uses the newer jazzier C optimized Class::C3
which is the new non-default standard for proper method-dispatch in all Perl's greater than Perl 5.95.[1]
Before Class::C3
and NEXT
, you had SUPER
which predates NEXT
by approximately six months and thankfully never made CORE. SUPER
was goofy and mostly useless because if foo and bar were siblings and subclasses of baz you could not re-dispatch in foo to a method in bar.
Essentially SUPER
supported Method Dispatch only for linear patterns. NEXT
supported them in a fashion that was quirky and made little sense.[2] Without learning the quirks there is a high probability the new Class::C3
does precisely what the programmer wants - it is intuitive. Class::C3
uses the C3 MRO algorithm which is also employed by Python.
The old way
editThe differences between NEXT
and Class::C3
are outside of the range of this book; but, because vanilla Perl doesn't even permit method resolution, and dispatch in the sense of the OO paradigm we will show NEXT
in its stead.
An Example
editpackage A;
use strict;
use warnings;
use NEXT;
sub name {
my $self = shift;
$self->{-name} = shift if @_;
return $self->{-name};
}
sub new {
my $obj = shift;
my $class = ref($obj)?ref($obj) : $obj;
my $args = shift;
my $self = bless {}, $class;
$self->{-name} = $args->{name} if( $args && ref($args) eq 'HASH' && $args->{name});
return $self;
}
sub say_name {
my $self = shift;
print "My name is ".$self->name.".\n";
}
package B
use strict;
use warnings;
use NEXT;
our @ISA = 'A'
package C
use strict;
use NEXT;
our @ISA = 'B'
sub say_name {
my $self = shift;
print "The name given to me is ".$self->name.".\n";
}
package main;
my $a = A->new({ name => 'Bob' });
# prints:
# My name is Bob
$a->say_name;
my $c = C->new({ name => 'Bill' });
#prints:
# The name given to me is Bill
$c->say_name;
Invoking the Moose
editAn Example
edit package A;
use Moose; # Includes strict and warnings
# Define an attribute the object instance has.
# In this case a name, which has a type of string, and
# has a read accessor and a write accessor.
has name => ( isa => 'Str', is => 'rw' );
sub say_name {
my $self = shift;
say " my name is ".$self->name.".\n";
}
no Moose; # Clean up the namespace.
package B;
use Moose;
no Moose;
package C;
use Moose;
sub say_name {
my $self = shift;
say "The name given to me is ".$self->name.".\n";
}
no Moose;
package main;
# We get new for free.
my $a = A->new({ name => 'Bob' });
# prints:
# My name is Bob
$a->say_name;
my $c = C->new({ name => 'Bill' });
#prints:
# The name given to me is Bill
$c->say_name;
External Links
editFootnotes
edit- ^ Perl 5.95 adds a new pragma mro which uses C3 resolution. This pragma is however opt in and makes a few tools available to you, which can all be utilized maintaining reverse compatibility with older Perl, using MRO::Compat.
- ^ The method that made little sense is called Depth First Search (DFS). DFS was the predecessor MRO to C3 in Perl. Briefly, it did not handle any form of triangle inheritance in a sane fashion.