Search code examples
perlmoosememoization

Is it possible to retrieve existing moose objects, rather than create a new one, when the same required attributes are provided?


Suppose i have the following Moose package:

package GSM::Cell;
use Moose;

has 'ID' => (is => 'ro', required => 1);
has [qw(BCCH NEIGHBOUR)] => (is => 'rw', default => undef);

no Moose;
__PACKAGE__->meta->make_immutable; 
1;

I then create two objects and add the one as the 'NEIGHBOUR' attribute of the other:

my $a = GSM::Cell->new(ID => 20021, BCCH => 1);
my $b = GSM::Cell->new(ID => 20022, BCCH => 2);
$a->NEIGHBOUR($b);

Somewhere else, e.g. in another procedure, the BCCH attribute of $b could be updated to another value:

$b->BCCH(3);

Now, if i refer to

 $a->NEIGHBOUR->BCCH

then i will still get back the initial value of the BCCH attribute instead of the updated value.

I guess the sensible thing to do is to add a reference to $b instead of $b itself which would solve the problem:

$a->NEIGHBOUR(\$b);

However, i have the scenario in a web application where an object equivalent to $b (same ID) is instantiated in a multitude of methods and changes could be done in any one, making it difficult to pass around references of all your created objects.

Ideally, when a call to

my $somevar = GSM::Cell->new(ID => 20022);

is made, an object should only be created if one with the same ID does not already exist.

Is a dictionary the way to go, something like this:

$id = 20022;
my $somevar = $already_created{$id} || GSM::Cell->new(ID => $id);

or are there neater solutions?


Solution

  • It sounds like something MooseX::NaturalKey was designed for.

    package GSM::Cell;
    use MooseX::NaturalKey;
    
    has 'ID' => (is => 'ro', required => 1);
    has [qw(BCCH NEIGHBOUR)] => (is => 'rw', default => undef);
    
    primary_key => ('ID');
    no Moose;
    __PACKAGE__->meta->make_immutable; 
    1;
    

    Then later:

    my $a = GSM::Cell->new(ID => 20021, BCCH => 1);
    my $b = GSM::Cell->new(ID => 20022, BCCH => 2);
    $a->NEIGHBOUR($b);
    $b->BCCH(3);
    say $a->NEIGHBOR->BCCH; # prints 3
    
    my $c = GSM::Cell->new(ID => 20022);
    $c->BCCH(4);
    say $a->NEIGHBOR->BCCH; # prints 4