Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 651
Ryan C. Thompson Avatar asked Feb 12 '11 00:02

Ryan C. Thompson


2 Answers

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;
    },
);
like image 167
Ether Avatar answered Oct 08 '22 09:10

Ether


Personally, I'd take advantage of laziness to ensure that I didn't get caught in an infinite recursion:

has start => (
  is => 'ro',
  isa => 'Int',
  lazy => 1,
  default => sub { shift->end },
  predicate => 'has_start',
);

has end => (
  is => 'ro',
  isa => 'Int',
  lazy => 1,
  default => sub { shift->start },
  predicate => 'has_end',
);

sub BUILD {
  my $self = shift;

  die "Need to specify at least one of 'start', 'end'!" 
    unless $self->has_start || $self->has_end;
}
like image 39
Piers Cawley Avatar answered Oct 08 '22 07:10

Piers Cawley