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

StackOverflow https://stackoverflow.com/questions/1807517

  •  05-07-2019
  •  | 
  •  

Question

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?

Was it helpful?

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

OTHER TIPS

  • Isn't the neighbour relationship between two cells in itself an object, that needs to be referenced by cells 20021 and 20022? Changing the BCC value on one cell could then be passed through to the relationship-object, thus updating both cells.

  • what you should do is store object references to your cells in a hash say $Network and control the cell creation through a factory class, that knows to check the $Network hash for existing cells...

I think the problem described in the first half of your post is a non-problem.

If I run your code:

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;

package main;

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

$b->BCCH(3);
print $a->NEIGHBOUR->BCCH, "\n";  # 3

It prints the updated value, not the old value. It works because $b is an object, and all Perl objects are blessed references. When you run $a->NEIGHBOUR($b) you are already passing a reference; there is no need to pass a reference to a reference.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top