Search code examples
perlattributesmoose

In Perl/Moose, can I have two attributes with mutually-dependent defaults?


Can I do this in Moose?

package SomeClass;
use Moose;

has start => (
    isa => 'Int',
    is => 'ro',
    lazy => 1,
    default => sub { $_[0]->end },
);

has end => (
    isa => 'Int',
    is => 'ro',
    lazy => 1,
    default => sub { $_[0]->start },
);

...

In other words, I want two attributes called "start" and "end", and if only one of them is specified, I want the other one to be set to the same thing. Not specifying either one is an error.

Does this mutually-dependent setup work?


Solution

  • Yes, if you remove the possibility of infinite recursion by verifying that at least one of these values is specified:

    has start => (
        ...
        predicate => 'has_start',
    );
    
    has end => (
        ...
        predicate => 'has_end',
    );
    
    sub BUILD
    {
        my $self = shift;
    
        die "Need to specify at least one of 'start', 'end'!" if not $self->has_start and not $self->has_end;
    }
    

    Alternatively, you could delay the check to the default subs:

    has start => (
        ...
        predicate => 'has_start',
        default => sub {
            my $self = shift;
            die "Need to specify at least one of 'start', 'end'!" if not $self->has_end;
            $self->end;
        },
    );
    
    has end => (
        ...
        predicate => 'has_end',
        default => sub {
            my $self = shift;
            die "Need to specify at least one of 'start', 'end'!" if not $self->has_start;
            $self->start;
        },
    );