Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Moose, how do I set multiple defaults with one method call?

Tags:

perl

moose

I have two object attributes which require expensive calculations, so I'd like them to be lazy. They're most efficiently calculated together, so I'd like to calculate them at the same time. Does Moose provide a way to do this?

What I'd like is something like 'default' or 'builder' but instead of returning the default value it directly sets attributes. The return value would be ignored.

has max_things =>
    is      => 'rw',
    isa     => 'Int',
    lazy    => 1,
    xxxxx   => '_set_maxes';

has max_pairs =>
    is      => 'rw',
    isa     => 'Int',
    lazy    => 1,
    xxxxx   => '_set_maxes';

# Let's just assume this is an expensive calculation or the max_*
# attributes are used rarely and a lot of objects are created.
sub _set_maxes {
    my $self = shift;

    if( $self->is_32_bit ) {
        $self->max_things(2**31);
        $self->max_pairs(12345 * 2);
    }
    else {
        $self->max_thing(2**63);
        $self->max_pairs(23456 * 2);
    }

    return;
}

NOTE: I could write my own 'reader' or use 'around', but I'd rather keep it declarative and let Moose do the work. I also could make a new object just to store the paired values, but it seems like overkill for just two values.

like image 781
Schwern Avatar asked Mar 06 '14 20:03

Schwern


1 Answers

I wouldn't say this is especially elegant, but it works...

use v5.14;
use warnings;

package Goose {
    use Moose;

    has max_things => (
        is      => 'rw',
        isa     => 'Int',
        lazy    => 1,
        default => sub { shift->_build_maxes->max_things },
    );

    has max_pairs => (
        is      => 'rw',
        isa     => 'Int',
        lazy    => 1,
        default => sub { shift->_build_maxes->max_pairs },
    );

    sub is_32_bit { 1 }

    sub _build_maxes {
        my $self = shift;

        warn "Running builder...";

        if( $self->is_32_bit ) {
            $self->max_things(2**31);
            $self->max_pairs(12345 * 2);
         }
         else {
            $self->max_thing(2**63);
            $self->max_pairs(23456 * 2);
        }

        $self;  # helps chaining in the defaults above
    }
}

my $goose = Goose->new;
say $goose->max_things;
say $goose->max_pairs;
like image 86
tobyink Avatar answered Nov 19 '22 02:11

tobyink