Belmark Caday
Belmark Caday

Reputation: 1683

Why declare a subroutine that returns a subroutine reference in Moose?

im new to Moose in perl, and i have been reading its documentation when i encountered this one which i dont quite understand:

If you want to use a reference of any sort as the default value, you must return it from a subroutine. OK i get this statement, and the next example

has 'mapping' => (
      is      => 'ro',
      default => sub { {} },
  );

This is necessary because otherwise Perl would instantiate the reference exactly once, and it would be shared by all objects: This one i dont understand, what does it mean that it would instantiate the reference exactly once and will be shared by all objects? How?

 has 'mapping' => (
      is      => 'ro',
      default => {}, # wrong!
  );

Moose will throw an error if you pass a bare non-subroutine reference as the default.

If Moose allowed this then the default mapping attribute could easily end up shared across many objects. Instead, wrap it in a subroutine reference as we saw above. Dont get this again

Upvotes: 0

Views: 96

Answers (1)

daxim
daxim

Reputation: 39158

Because it creates action at a distance, which is bad. Illustration of the problem:

package Wrong;
my $default = {};

sub new {
    my ($class) = @_;
    return bless $default => $class;
}

package main;
use 5.010;
my @wobj;
push @wobj, Wrong->new for 0..2;

$wobj[0]->{some_new_attr} = 'foobar';

use Data::Dumper qw(Dumper);
print Dumper $wobj[1];  # huh????!
print Dumper $wobj[2];  # that one, too?! why?

say for @wobj;          # ah, it's the same shared address

package Correct;
my $default = sub { return {} };

sub new {
    my ($class) = @_;
    return bless $default->() => $class;
}

package main;
my @cobj;
push @cobj, Correct->new for 0..2;

$cobj[0]->{some_new_attr} = 'foobar';

print Dumper $cobj[$_] for 0..2; # instances 1 and 2 are unaffected

say for @cobj;          # all different addresses

Upvotes: 2

Related Questions