info > Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion

Moose::CookMoose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion(3pm)

NAME
       Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion -
       Operator overloading, subtypes, and coercion

VERSION
       version 2.2200

SYNOPSIS
         package Human;

         use Moose;
         use Moose::Util::TypeConstraints;

         subtype 'Sex'
             => as 'Str'
             => where { $_ =~ m{^[mf]$}s };

         has 'sex'    => ( is => 'ro', isa => 'Sex', required => 1 );

         has 'mother' => ( is => 'ro', isa => 'Human' );
         has 'father' => ( is => 'ro', isa => 'Human' );

         use overload '+' => \&_overload_add, fallback => 1;

         sub _overload_add {
             my ( $one, $two ) = @_;

             die('Only male and female humans may create children')
                 if ( $one->sex() eq $two->sex() );

             my ( $mother, $father )
                 = ( $one->sex eq 'f' ? ( $one, $two ) : ( $two, $one ) );

             my $sex = 'f';
             $sex = 'm' if ( rand() >= 0.5 );

             return Human->new(
                 sex    => $sex,
                 mother => $mother,
                 father => $father,
             );
         }

DESCRIPTION
       This Moose cookbook recipe shows how operator overloading, coercion,
       and subtypes can be used to mimic the human reproductive system (well,
       the selection of genes at least).

INTRODUCTION
       Our "Human" class uses operator overloading to allow us to "add" two
       humans together and produce a child. Our implementation does require
       that the two objects be of opposite sex. Remember, we're talking about
       biological reproduction, not marriage.

       While this example works as-is, we can take it a lot further by adding
       genes into the mix. We'll add the two genes that control eye color, and
       use overloading to combine the genes from the parent to model the
       biology.

   What is Operator Overloading?
       Overloading is not a Moose-specific feature. It's a general OO concept
       that is implemented in Perl with the "overload" pragma. Overloading
       lets objects do something sane when used with Perl's built in
       operators, like addition ("+") or when used as a string.

       In this example we overload addition so we can write code like "$child
       = $mother + $father".

GENES
       There are many genes which affect eye color, but there are two which
       are most important, gey and bey2. We will start by making a class for
       each gene.

   Human::Gene::bey2
         package Human::Gene::bey2;

         use Moose;
         use Moose::Util::TypeConstraints;

         type 'bey2_color' => where { $_ =~ m{^(?:brown|blue)$} };

         has 'color' => ( is => 'ro', isa => 'bey2_color' );

       This class is trivial. We have a type constraint for the allowed
       colors, and a "color" attribute.

   Human::Gene::gey
         package Human::Gene::gey;

         use Moose;
         use Moose::Util::TypeConstraints;

         type 'gey_color' => where { $_ =~ m{^(?:green|blue)$} };

         has 'color' => ( is => 'ro', isa => 'gey_color' );

       This is nearly identical to the "Humane::Gene::bey2" class, except that
       the gey gene allows for different colors.

EYE COLOR
       We could just give four attributes (two of each gene) to the "Human"
       class, but this is a bit messy. Instead, we'll abstract the genes into
       a container class, "Human::EyeColor". Then a "Human" can have a single
       "eye_color" attribute.

         package Human::EyeColor;

         use Moose;
         use Moose::Util::TypeConstraints;

         coerce 'Human::Gene::bey2'
             => from 'Str'
                 => via { Human::Gene::bey2->new( color => $_ ) };

         coerce 'Human::Gene::gey'
             => from 'Str'
                 => via { Human::Gene::gey->new( color => $_ ) };

         has [qw( bey2_1 bey2_2 )] =>
             ( is => 'ro', isa => 'Human::Gene::bey2', coerce => 1 );

         has [qw( gey_1 gey_2 )] =>
             ( is => 'ro', isa => 'Human::Gene::gey', coerce => 1 );

       The eye color class has two of each type of gene. We've also created a
       coercion for each class that coerces a string into a new object. Note
       that a coercion will fail if it attempts to coerce a string like
       "indigo", because that is not a valid color for either type of gene.

       As an aside, you can see that we can define several identical
       attributes at once by supplying an array reference of names as the
       first argument to "has".

       We also need a method to calculate the actual eye color that results
       from a set of genes. The bey2 brown gene is dominant over both blue and
       green. The gey green gene is dominant over blue.

         sub color {
             my ($self) = @_;

             return 'brown'
                 if ( $self->bey2_1->color() eq 'brown'
                 or $self->bey2_2->color() eq 'brown' );

             return 'green'
                 if ( $self->gey_1->color() eq 'green'
                 or $self->gey_2->color() eq 'green' );

             return 'blue';
         }

       We'd like to be able to treat a "Human::EyeColor" object as a string,
       so we define a string overloading for the class:

         use overload '""' => \&color, fallback => 1;

       Finally, we need to define overloading for addition. That way we can
       add together two "Human::EyeColor" objects and get a new one with a new
       (genetically correct) eye color.

         use overload '+' => \&_overload_add, fallback => 1;

         sub _overload_add {
             my ( $one, $two ) = @_;

             my $one_bey2 = 'bey2_' . _rand2();
             my $two_bey2 = 'bey2_' . _rand2();

             my $one_gey = 'gey_' . _rand2();
             my $two_gey = 'gey_' . _rand2();

             return Human::EyeColor->new(
                 bey2_1 => $one->$one_bey2->color(),
                 bey2_2 => $two->$two_bey2->color(),
                 gey_1  => $one->$one_gey->color(),
                 gey_2  => $two->$two_gey->color(),
             );
         }

         sub _rand2 {
             return 1 + int( rand(2) );
         }

       When two eye color objects are added together, the "_overload_add()"
       method will be passed two "Human::EyeColor" objects. These are the left
       and right side operands for the "+" operator. This method returns a new
       "Human::EyeColor" object.

ADDING EYE COLOR TO "Human"s
       Our original "Human" class requires just a few changes to incorporate
       our new "Human::EyeColor" class.

         use List::Util 1.56 qw( mesh );

         coerce 'Human::EyeColor'
             => from 'ArrayRef'
             => via { my @genes = qw( bey2_1 bey2_2 gey_1 gey_2 );
                      return Human::EyeColor->new( mesh ( \@genes, $_ ) ); };

         has 'eye_color' => (
             is       => 'ro',
             isa      => 'Human::EyeColor',
             coerce   => 1,
             required => 1,
         );

       We also need to modify "_overload_add()" in the "Human" class to
       account for eye color:

         return Human->new(
             sex       => $sex,
             eye_color => ( $one->eye_color() + $two->eye_color() ),
             mother    => $mother,
             father    => $father,
         );

CONCLUSION
       The three techniques we used, overloading, subtypes, and coercion,
       combine to provide a powerful interface.

       If you'd like to learn more about overloading, please read the
       documentation for the overload pragma.

       To see all the code we created together, take a look at
       t/recipes/basics_genome_overloadingsubtypesandcoercion.t.

NEXT STEPS
       Had this been a real project we'd probably want:

       Better Randomization with Crypt::Random
       Characteristic Base Class
       Mutating Genes
       More Characteristics
       Artificial Life

AUTHORS
       o   Stevan Little <stevan AT cpan.org>

       o   Dave Rolsky <autarch AT urth.org>

       o   Jesse Luehrs <doy AT cpan.org>

       o   Shawn M Moore <sartak AT cpan.org>

       o    ' (Yuval Kogman) <nothingmuch AT woobling.org>

       o   Karen Etheridge <ether AT cpan.org>

       o   Florian Ragwitz <rafl AT debian.org>

       o   Hans Dieter Pearcey <hdp AT cpan.org>

       o   Chris Prather <chris AT prather.org>

       o   Matt S Trout <mstrout AT cpan.org>

COPYRIGHT AND LICENSE
       This work is licensed under a Creative Commons Attribution 3.0 Unported
       License.

       License details are at: <http://creativecommons.org/licenses/by/3.0/>

perl v5.34.Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion(3pm)
Moose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion
Moose::CookMoose::Cookbook::Basics::Genome_OverloadingSubtypesAndCoercion(3pm) NAME VERSION SYNOPSIS DESCRIPTION INTRODUCTION GENES EYE COLOR CONCLUSION NEXT STEPS AUTHORS COPYRIGHT AND LICENSE

Generated by phpman v4.9.22-1-g1b0fcb4 · Markdown · JSON · MCP Author: Che Dong Under GNU General Public License
2026-07-05 06:05 @216.73.216.52
CrawledBy Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
Valid XHTML 1.0 Transitional!Valid CSS!

^_top_^