Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

Child objects querying parent objects about themselves

by vaevictus (Pilgrim)
on Nov 13, 2002 at 17:48 UTC ( #212644=perlquestion: print w/replies, xml ) Need Help??

vaevictus has asked for the wisdom of the Perl Monks concerning the following question:

I've got a parent object that in it's ($self) contains a two dimentional array of child objects.

While I understand that I can tell the parent to pass the indices (coordinates) to each of the child objects at some time, is there any way for the child to query the parent object to determine what it's coordinates are?

The objects i'm currently using are perltoot style objects, and might look something like this:

package Parent; use Child; sub new { my $that = shift; my $class = ref($that) || $that; my $self = { children=>undef; }; bless($self, $class); $self->init(); return $self; } sub init { my $xmax=5; my $ymax=5; foreach my $x (0 .. $xmax) { foreach my $y (0 .. $ymax) { $self->{'children'}[$x][$y]=Child->new($self); } } } package Child; use Parent; sub new { my $that = shift; my $class = ref($that) || $that; my $parent = shift; my $self = { parent => \$parent; }; bless($self, $class); return $self; } sub whereami { #i don't know how to ask the parent here; }

Replies are listed 'Best First'.
Re: Child objects querying parent objects about themselves
by jdporter (Chancellor) on Nov 13, 2002 at 17:55 UTC
    You are faced with a classic time-vs-space tradeoff.

    You can either:

    • store each child's coordinates in itself (redundant, and possibly risking sync problems);
    • store the children in a hash as well as the arrays in the parent; or
    • do a brute-force look-up of the child each time it wants the info.

    ...porque es dificil estar guapo y blanco.

Re: Child objects querying parent objects about themselves
by dash2 (Hermit) on Nov 13, 2002 at 18:21 UTC
    sub whereami { my $self = shift; $self->{parent}->locate($self); } # in Parent sub locate { my $self = shift; my $child = shift; foreach my $x (0 .. $xmax) { foreach my $y (0 .. $ymax) { return ($x, $y) if $self->{children}[$x][$y] eq $child; } } }

    So that is how to do it - use the reference as a string. But do you want to do that?

    TMTOWTDI. You could also store x and y information in the child objects. The parent could have a simple array of kids and grep through them for the right X and Y. Or you could pass the x and y on child creation and store the info in two places. Make sure that if you change that info, you change it in both places - use a single subroutine for changing x and y. Again, the subroutine could either be in the Parent class or the Child class, but it will operate on both objects.

    A method is just a subroutine with an extra argument.

    sub foobar { my $foo = shift; my $bar = shift; # do stuff }

    is no different from

    sub foobar { my $bar = shift; my $foo = shift; # do stuff }

    as a subroutine. So in that sense, where you put your info is not that relevant. (Of course, inheritance is different. But that may not be an issue for you.)

    So how do you choose? Well: do objects need to know the x and y of other objects? If so, that info needs to be publicly accessible in the Parent, using the locate method above. If objects only need to know where they are themselves, keep info in the Child.

    Also, it looks to me as if x and y refer to co-ordinates. If so, do you really want a 2d array? This will make it easy to find columns:

     @{ $self->{children}[$col] };

    but awkward to find rows:

    grep {$_->[$row]} @{$self->{children}}; # I think!

    There is probably a solution on CPAN for grids... maybe Meta::Geo::Pos2d ? if not, there is certainly a full featured Array class that will make this stuff easier.

    dave hj~

Re: Child objects querying parent objects about themselves
by jjore (Initiate) on Nov 13, 2002 at 17:59 UTC

    I'll just add to jdporter's node that you ought not to do a 'use Parent' inside your Child package. It already gets a Parent object via Child->new($self). Since you're doing OO you can also switch to 'require Child' (assuming you split this into separate files) since 'use' just happens earlier and runs import() - a superfluous operation for your code.

Re: Child objects querying parent objects about themselves
by robartes (Priest) on Nov 13, 2002 at 18:10 UTC
    You could create accessor functions in the parent that access the children arrays, like:
    # Parent sub get_child_id { my $self=shift; my $child=shift; # Find the index of the child. Left as exercise for the reader (read +: I'm too lazy :) ). return $child_index; }
    Then your child can get its ID using code such as:
    # Child sub whereami { my $self=shift; my $parent=$self->{'parent'}; my $id=$parent->get_child_id($self); }
    Note that you have a small error in your child code, BTW: you store a reference to the reference to the parent instead of the parent ref itself. Change the line:
    my $self = { parent => \$parent; };
    my $self= { parent => $parent }; #$parent is a ref, you were storing a + ref to $parent


    Update: Changed child sub name to original poster's name: sub whereami.

      Thanks. As far as the \$parent typo, i've already got it correct in my code... just not when i typed it into SOPW. Thanks for the heads up though.

      As for the method you described ... this is probably the best way to do it... naturally... if this becomes too much overhead, i'll have to make the coords redundant somewhere, as described in jdporter's comment.

        An object oriented principial dilema arises from such redundancy - should the child object be responsible for it's location in the parent (knowing and/or maintaining)?
        Some will argue that since the children heriarchly exist within the parent, then the responsibility should only be the parent's...
        This is perhaps analogeous to the question of wether you should use method objects within sibling methods, or access the object internals directly.
        Think about it.

        In addition, perhaps Tie::RefHash may be of use for maintaing a hash of references to the child objects, within the parent. The parent can simply lookup child by it's object reference, and in the hash will be the coordinate values.

        zz zZ Z Z #!perl

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://212644]
Approved by diotalevi
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2022-05-16 09:45 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (62 votes). Check out past polls.