Jump to content

Programming with Moose/Problems solved

From Wikibooks, open books for an open world

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

[edit | edit source]

The 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

[edit | edit source]
package 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

[edit | edit source]

An Example

[edit | edit source]
  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;
[edit | edit source]

Footnotes

[edit | edit source]
  1. ^ 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.
  2. ^ 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.