Give the below code, it appears that the order you instatiate the objects matter. The below code will print the same list for both objects when i would expect a different list for each because list is an instance attribute that is created at BUILD time.
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
default => sub {\@list}
);
1;
---
package u;
use Moo;
use Types::Standard qw(ArrayRef);
extends 't';
sub BUILD {
my ($self) = @_;
push @{$self->list()}, qw/apple banana/;
return $self;
}
1;
---
#!perl
use Data::Printer;
use t;
use u;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
Current Output:
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
Expected output:
\ [
[0] "foo",
[1] "bar",
[2] "baz",
[3] "apple",
[4] "banana"
]
\ [
[0] "foo",
[1] "bar",
[2] "baz"
]
Since you mutate the array in question, you don't want a reference to the array that you use as the default \@list
, you want to take a shallow copy [@list]
.
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
builder =>
default => sub { [@list] }
);
package u;
use Moo;
use Types::Standard qw(ArrayRef);
extends 't';
sub BUILD {
my ($self) = @_;
push @{$self->list()}, qw/apple banana/;
return $self;
}
package main;
use Data::Printer;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
While I'm at it, using BUILD to modify an attribute is possible but not necessarily the best. You can use something like a lazy attribute with a builder method, then overload that method in the subclass, ala
package t;
use Moo;
use Types::Standard qw(ArrayRef);
my @list = qw/foo bar baz/;
has list => (
is => 'rw',
isa => ArrayRef,
builder => '_build_list',
lazy => 1,
);
sub _build_list {
my $self = shift;
return [@list];
}
package u;
use Moo;
extends 't';
sub _build_list {
my $self = shift;
my $list = $self->SUPER::_build_list();
push @$list, qw/apple banana/;
return $list;
}
package main;
use Data::Printer;
my $u = u->new();
p $u->list();
my $t = t->new();
p $t->list();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With