Object Member List Instances

J

julians

Here's an interesting simplified version of a problem I have:

I have parent objects that have a list of child objects.

I want the list of children that belong to each parent to belong to
that instance of the parent object only. What I'm getting is a shared
list among the parent objects and I don't want that.

Here's the code...

#Beginning of file Child.pm

package Child;

sub new {
my $invocant = shift;
my $self = bless({}, ref $invocant || $invocant);
$self->init();
return $self;

}

sub init {
my $self = shift;
$self->id("0");
$self->name("unnamed");

}

for my $field (qw(id name)) {
my $slot = __PACKAGE__ . "::$field";
no strict "refs";
*$field = sub {
my $self = shift;
$self->{$slot} = shift if @_;
return $self->{$slot};
};

}
1;

#End of file Child.pm


#Beginning of file Parent.pm

package Parent;
use Child;

sub new {
my $invocant = shift;
my $self = bless({}, ref $invocant || $invocant);
$self->init();
return $self;

}

sub init {
my $self = shift;
$self->id("0");
$self->name("unnamed");
$self->childList({});

#running this will destroy all the parent's children,
#not just this instances' children as it's supposed to.
#foreach my $childListIndex (keys %self::childList) {
# delete $self::childList{$childListIndex};
#
#}

}

sub addChild {
my ($self, $childToAdd) = @_;

$self::childList{$childToAdd->id} = {
"child" => $childToAdd,
};

}


sub displayChildList {
my $self = shift;
foreach my $childListIndex (keys %self::childList) {
my $thisChildOut = Child::->new;
$thisChildOut = $self::childList{$childListIndex}{child};
print("\tChild belonging to parent ID " . $self->id . "\n");
print("\tChild ID = " . $thisChildOut->id . "\n");
print("\tChild Name = " . $thisChildOut->name . "\n");
print("\n");

}

}


for my $field (qw(id name childList)) {
my $slot = __PACKAGE__ . "::$field";
no strict "refs";
*$field = sub {
my $self = shift;
$self->{$slot} = shift if @_;
return $self->{$slot};
};

}
1;

#End of file Parent.pm


#Beginning of file test.pl

use strict;
use warnings;
use Parent;
use Child;

my $child1 = Child::->new;
$child1->id("1");
$child1->name("Cecil");

my $child2 = Child::->new;
$child2->id("2");
$child2->name("Eddy");

my $child3 = Child::->new;
$child3->id("3");
$child3->name("Dolph");

my $child4 = Child::->new;
$child4->id("4");
$child4->name("Cyrus");

my $parent1 = Parent::->new;
$parent1->id("1");
$parent1->name("Thelma");
$parent1->addChild($child1);
$parent1->addChild($child4);
print("Children of " . $parent1->name . "\n");
$parent1->displayChildList();

my $parent2 = Parent::->new;
$parent2->id("2");
$parent2->name("Magdalene");
$parent2->addChild($child3);
$parent2->addChild($child2);
print("Children of " . $parent2->name . "\n");
$parent2->displayChildList();

print("Children of " . $parent1->name . "\n");
$parent1->displayChildList();

#End of file test.pl

ran with the command
perl -w test.pl


Output is as follows:

Children of Thelma
Child belonging to parent ID 1
Child ID = 4
Child Name = Cyrus

Child belonging to parent ID 1
Child ID = 1
Child Name = Cecil

Children of Magdalene
Child belonging to parent ID 2
Child ID = 4
Child Name = Cyrus

Child belonging to parent ID 2
Child ID = 1
Child Name = Cecil

Child belonging to parent ID 2
Child ID = 3
Child Name = Dolph

Child belonging to parent ID 2
Child ID = 2
Child Name = Eddy

Children of Thelma
Child belonging to parent ID 1
Child ID = 4
Child Name = Cyrus

Child belonging to parent ID 1
Child ID = 1
Child Name = Cecil

Child belonging to parent ID 1
Child ID = 3
Child Name = Dolph

Child belonging to parent ID 1
Child ID = 2
Child Name = Eddy


How do I fix this so I get seperate lists?
Thanks
Julian
 
J

John Bokma

Here's an interesting simplified version of a problem I have:

I have parent objects that have a list of child objects.
....

How do I fix this so I get seperate lists?

Had a very quick peek, but how about (Child:

sub new {

my ( $invocant, $id, $name ) = @_;
my $self = bless({

id => $id,
name => $name,

}, ref $invocant || $invocant);

return $self;
}

my $child1 = new Child( '1', 'Cecil' );
 
J

John Bokma

John Bokma said:
Had a very quick peek, but how about (Child:

sub new {

my ( $invocant, $id, $name ) = @_;
my $self = bless({

id => $id,
name => $name,

}, ref $invocant || $invocant);

return $self;
}

my $child1 = new Child( '1', 'Cecil' );

Oh, if you want your IDs to be unique:

my $ids = ( );

sub new {

return __PACKAGE__; # singleton
}

sub id {

my ( undef, $id, $value ) = @_;

if ( @_ == 3 ) {

$ids{ $id } = { value => $value };
return;
}

return $ids{ $id }->{value};
}

# ditto for name
 
J

julians

I think the problem lies with either the way I declare the list in
Parent.pm

$self->childList({});

or more likely with the way the list is being prototyped along with the
other Parent members in the

for my $field (qw(id name childList)) {

statement. I've unrolled that a bit to make it more readable. Here's
what is actually happening.

*{"childList"} = sub {
my $self = shift;
$self->{"Child::childList"} = shift if @_;
return %self::childList;
};

I don't think that works too well for lists. I suspect that code is
what makes all the Parent objects share the same childList rather than
have their own individual ones.

For anyone who's curious, just pull out the code listing at the start
of this thread and put them into the appropriately named files (see the
comments). Run it with the command I gave and see what I mean.

Enjoy
Julian
 
B

Big and Blue

I want the list of children that belong to each parent to belong to
that instance of the parent object only.

So make it a list of refernces to the children, not a list of children.

sub addChild {
my ($self, $childToAdd) = @_;

$self::childList{$childToAdd->id} = {
"child" => $childToAdd, "child" => \$childToAdd,
};

And adjust use of this hash item to reflect it now a being a reference.
E.g.:
sub displayChildList {
my $self = shift;
foreach my $childListIndex (keys %self::childList) {
my $thisChildOut = Child::->new;
$thisChildOut = $self::childList{$childListIndex}{child};
$thisChildOut = {$self::childList{$childListIndex}{child}};
print("\tChild belonging to parent ID " . $self->id . "\n");
etc.
 
J

julians

I tried out the exact suggestions you made, but it made no difference
to the output. I believe the problem lies in the prototyping of the
list or the declaration itself.

Thanks though,
Julian
 
J

julians

Sorry, in file Parent.pm that should be...

*{"childList"} = sub {
my $self = shift;
$self->{"Parent::childList"} = shift if @_;
return %self::childList;

};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top