views:

199

answers:

3

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?

+2  A: 
  • 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...

lexu
@lexu: In my actual code (the above example was contrived for brevity purposes) the neighbour relationship is represented by an object with references to both cells. However this still does not solve the problem when another cell with same ID as 20022 is created (somewhere else in the code) as there is no simple way to reference this newly created object to the one that is linked in the neighbour relationship (unless i am missing something?). Your idea of $Network and controlling cell creation through a factory class could do the trick though .. thanks !
Hartmut Behrens
@lexu: The factory class idea works nicely - thanks !
Hartmut Behrens
I am still open to other interesting responses though ??
Hartmut Behrens
@Hartmut Behrens: look at peregrin's answer .. "there's a module for that": http://stackoverflow.com/questions/1807517/is-it-possible-to-retrieve-existing-moose-objects-rather-than-create-a-new-one/1809231#1809231
lexu
+1  A: 

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.

FM
+3  A: 

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
perigrin
MooseX::NaturalKey would be an ideal solution, however it does not appear to do what it advertises : http://www.cpantesters.org/distro/M/MooseX-NaturalKey.htmlDid you get the example above to work?
Hartmut Behrens
It seems MooseX-NaturalKey was written with an older version of Class-MOP-Class in mind. If the line "override construct_instance => sub {" is changed to "override new_object => sub {" in MooseX::NaturalKey::Meta::Class then MooseX::NaturalKey works as expected.
Hartmut Behrens
I admit to not having tried the example above. I would file a bug and follow up with Sam (mugwump on IRC). He's pretty responsive.
perigrin
In fact I just pinged him on IRC and it sounds like he knew exactly what the problem is and is fixing it.
perigrin