Search code examples
perlmoo

Why does Moo's builder method have access to only some of the other attributes?


I was expecting a builder method to have access to all the other attributes provided by the caller. But it seems it only has access to those whose name is alphabetically less than the current attribute's. E.g. why can the builder for b here see the value of a but not c? (Both 'a' and 'c' are present in the final object)

Code:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;
{
    package P;
    use Moo;

    printf "Moo version: %s\n", $Moo::VERSION;

    # a and c are defined in the same way
    has a => ( is => 'ro' );
    has c => ( is => 'ro' );
    has b => (
        is => 'ro',
        builder => '_build_b',
    );

    sub _build_b {
        my ($self) = @_;
        print Data::Dumper->new(
            [ $self ], [ 'self_during_build_b' ]
        )->Indent(1)->Sortkeys(1)->Dump;
        return "somebuiltvalue";
    }
}
my $p = P->new({ a => 1, c => 3 });
print Data::Dumper->new([$p],['p'])->Indent(1)->Sortkeys(1)->Dump;

Output:

Moo version: 2.003004
$self_during_build_b = bless( {
  'a' => 1
}, 'P' );
$p = bless( {
  'a' => 1,
  'b' => 'somebuiltvalue',
  'c' => 3
}, 'P' );

Solution

  • In fact, you should not assume anything about any other fields in the builder for a specific member. If the value of some member of your class depends on the values of one or more other members, then the appropriate place to handle that would be the class BUILD method.

    I don't know exactly what you are trying to achieve, but are you looking for lazy?

    Or, maybe b needs to be a method in your class