Search code examples
perlinitializationmoose

How should I define a Moose object subroutine after its initialization?


How should I define a Moose object subroutine after its initialization?

I'm writing an object module using Moose and I plan to serialize (nstore) the created objects.

Examine the following (simplified!) example:

package MyObj 0.001;

use Moose;
use namespace::autoclean;

has 'size' => (
 is       => 'ro',
 isa      => 'Int',
 required => 1,
);

sub some_sub {
 my ($self, @more) = @_;
 if ($self->size() < 100) # do something;
 elsif (($self->size() < 500)) # do something else;
 elsif (($self->size() < 7500)) # do something else;
 # ...
}

1;

some_sub acts differently depending on size. Since size is read-only, it remains constant after the object has been initialized.

So, assuming I call some_sub zillion times, it's a pity that I have to go through all the ifs each time.

I'd better do this once after the object has been initialized, then set some_sub to be a simpler function with noifs at all.

But... how can I do that?

UPDATE

Perhaps I should add a lazy attribute of type subref that will hold a reference to the chosen subroutine. some_sub will then simply call $self->chosen_sub->(@_). What do you think?


Solution

  • has calculation_method => (is => 'ro', lazy_build => 1, init_arg => undef);
    
    sub _build_calculation_method {
        my $self = shift;
        return '_calculate_small'  if $self->size < 100;
        return '_calculate_medium' if $self->size < 500;
        return '_calculate_large'  if $self->size < 7500;
        return '_calculate_enormous';
    }
    
    sub _calculate_small  { ... }
    sub _calculate_medium { ... }
    # etc.
    
    sub calculate {
        my $self = shift;
        my $method = $self->calculation_method;
        return $self->$method(@_);
    }
    

    As a bonus, calculation_method is now serializable too.