Search code examples
perlmoose

How can I overload Moose constructors?


Sorry for the Java jargon, but how can I overload Moose constructors?

Suppose I'm representing a segment. I can either take a start point and and point, or a start point and length, or end point and length.

How can I allow for such alternative construction methods?


Solution

  • You don't need to override new. You can supply your own BUILD:

    #!/usr/bin/perl
    
    package My::Segment;
    
    use Moose;
    use namespace::autoclean;
    use Carp qw( confess );
    
    has 'start' => (is => 'ro', isa => 'Num',
        predicate => 'has_start', writer => '_set_start',
    );
    
    has 'end' => (is => 'ro', isa => 'Num',
        predicate => 'has_end', writer => '_set_end',
    );
    
    has 'length' => (is => 'ro', isa => 'Num',
        predicate => 'has_length', writer => '_set_length',
    );
    
    sub BUILD {
        my $self = shift;
    
        $self->has_start and $self->has_end and $self->length and do {
            return if $self->length == $self->end - $self->start;
            confess "Inconsistent start, end and length";
        };
    
        $self->has_start and $self->has_end and do {
            $self->_set_length($self->end - $self->start);
            return;
        };
        $self->has_start and $self->has_length and do {
            $self->_set_end($self->start + $self->length);
            return;
        };
        $self->has_end and $self->has_length and do {
            $self->_set_start($self->end - $self->length);
            return;
        };
        confess "At least two of start, end or length must be supplied";
    }
    
    __PACKAGE__->meta->make_immutable;
    
    package main;
    use YAML;
    
    my $x = My::Segment->new(start => 0, length => 3);
    my $y = My::Segment->new(start => 1, end => 4);
    my $z = My::Segment->new(end => 5, length => 3);
    
    print Dump($_) for $x, $y, $z;
    
    my $w = My::Segment->new(start => 0, end => 0, length => 1);