Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

OO: sharing data across inheritance

by skillet-thief (Friar)
on Jun 02, 2004 at 09:53 UTC ( #359306=perlquestion: print w/replies, xml ) Need Help??

skillet-thief has asked for the wisdom of the Perl Monks concerning the following question:

I'm am still working on my comprehension of OO in Perl. I think I more or less grasp the general ideas but am having some trouble with the more practical applications.

Here is my current problem. I want to have a Parent class that has a new_child() method that blesses a new objet into the Child class that inherits from Parent. That should give me something like this, in the script that uses these modules:

#pseudocode, of course #!/usr/bin/perl use warnings; use strict; use Parent; my %data = ( param1 => "something", param2 => "something else"); my $p = Parent->new(\%data); my $c = $p->new_child("More data");

I would like to have param1, for example, be available to $c. Do I need to copy it explicitly in the constructor, by doing something like this in Parent.pm? (I know this would work, but I'm not sure that it is the best way to acheive what I want.)

sub new_child { my $self = shift; my $more_data = shift; bless { param1 => $self->{param1}, more_data => $more_data }, "Child"; }
Or is there some way for $c to refer to what is in $p?

Or am I hopelessly off target on this whole thing?

Thanks and cheers,

s-t

Replies are listed 'Best First'.
Re: OO: sharing data across inheritance
by merlyn (Sage) on Jun 02, 2004 at 10:05 UTC
      In traditional OO, your child class inherits the behavior of the parent class, not the data of a specific parent object.
      Yeah, but the de facto Perl standard of doing OO means you do inherit all the data of a specific parent object.

      Abigail

Re: OO: sharing data across inheritance
by saskaqueer (Friar) on Jun 02, 2004 at 10:02 UTC

    Perhaps you want something like what I've posted below? It keeps a copy of the options passed to the parent constructor and passes them, along with any new options, to the child constructor. I'm not sure if it's something like this you are looking for, or if I am way off base.

    update: Added an iterator to the main script to show results of child creation. In a real-world example, you'd probably want methods to access the children, rather than digging around in the package internals as I have done below.

    package Parent; use strict; use Child; sub new { my ($class, %opts) = @_; my $self = bless( { _opts => \%opts, # save parent options _children => [] # an array of children }, $class); return $self; } sub new_child { my ($self, %opts) = @_; my $child = Child->new( %{ $self->{_opts} }, # the saved parent options %opts # the new child options ); # save this child inside the parent object push @{ $self->{_children} }, $child; return $child; } 1; package Child; use strict; sub new { my ($class, %opts) = @_; my $self = bless( { _opts => \%opts }, $class ); return $self; } 1; package main; use strict; use Parent; # Create the parent object. We will create child objects # with it and save those child objects within the parent. my $p = Parent->new( foo => 1, bar => 2 ); # Create the first child. Pass an extra option in. my $c1 = $p->new_child( baz => 3 ); # Create a second child. Give it different options. my $c2 = $p->new_child( qux => 4, yeah => 5 ); # Iterate through children and see which options they got. for my $child ( @{ $p->{_children} } ) { while ( my ($k, $v) = each %{ $child->{_opts} } ) { print "$k ==> $v\n"; } print "\n"; }

      Wow, thanks for the lightning fast and enlightening response. This looks like what I was thinking about, but I have one more question.

      Is it necessary to store the children in the parent, like what you do in the Parent package:

      # save this child inside the parent object push @{ $self->{_children} }, $child;
      Or is it enough to pass the child a reference to the %opts?

      And thanks!

      s-t

        No, you do not need to save the children within the parent. I only did that as an example. If your project doesn't require that the parent keep track of the children it creates, then you can safely remove that section.

Re: OO: sharing data across inheritance
by adrianh (Chancellor) on Jun 02, 2004 at 10:54 UTC
    Or am I hopelessly off target on this whole thing?

    Possibly :-) As merlyn says it looks like you're trying to inherit state rather than behaviour, which is the opposite of what most object oriented systems do.

    Can you describe the problem that you're trying to solve with Parent and Child? There may be another way of attacking the problem.

      Can you describe the problem that you're trying to solve with Parent and Child? There may be another way of attacking the problem.

      I am starting to think that "another way" might be in order here. Here is basically what I am trying to do:

      I am writing an LWP interface to an automated web publishing system. My interface already works, but is written as subroutines to which you have to pass lots of variables each time. Since my scripts are intended to be used by others, I wanted to clean them up and avoid passing around the same variables all the time. That is why I decided to do an OO rewrite.

      More specifically: There is a certain amount of information that goes with the website to which the user publishes: passwords, directories, etc. Inside that site, there is a series of "journal issues" that have their own specific information, but they of course share the information pertaining to the site.

      The relationship between Parent and Child in my original post was intended to describe these two different levels. I was thinking of the kind of relationship that exists, in DBI.pm, for example, between the database handle ($dbh) and the individual query objects ($sth).

      So you are right about state. My Parent class is indeed intended to maintain state, while the Child class was supposed to actually do the real work. Does this mean that I should abandon an OO approach, or just quit trying inheritance?

      Should my state data just be a class variable?

      s-t

        I am writing an LWP interface to an automated web publishing system. My interface already works, but is written as subroutines to which you have to pass lots of variables each time. Since my scripts are intended to be used by others, I wanted to clean them up and avoid passing around the same variables all the time. That is why I decided to do an OO rewrite.

        Lots of state information being passed around. Sounds exactly the sort of thing that belongs in one or more objects - so I think your instincts to move to an OO model are spot on.

        More specifically: There is a certain amount of information that goes with the website to which the user publishes: passwords, directories, etc. Inside that site, there is a series of "journal issues" that have their own specific information, but they of course share the information pertaining to the site.

        So a the Website has multiple JournalIssues - yes?

        So you are right about state. My Parent class is indeed intended to maintain state, while the Child class was supposed to actually do the real work. Does this mean that I should abandon an OO approach, or just quit trying inheritance?

        I think an OO approach is the right one, but I don't think that the relationship between Websites and JournalIssues is best modelled by inheritance.

        Inheritance is used for modeling is-a relations. If it doesn't make sense to say that a JournalIssue is-a Website then inheritance is probably not the right solution to pick.

        Just like the $dbh and $sth objects in DBI. A statement handle isn't a kind of database handle.

        Instead you might want to look at having your Website maintain a list of JournalIssue objects internally.

        Without knowing more about your application its a bit difficult to talk about specifics. I'd recommend trying to migrate to your OO model in a set of smaller steps.

        If you see a bunch of state that your passing to every function wrap that up in an object and pass that instead. Do that a few times and you'll probably start seeing some of the subroutines as candidate methods for that object. Let the code guide you and you'll probably see some classes fall out fairly easily.

Re: OO: sharing data across inheritance
by cyocum (Curate) on Jun 02, 2004 at 10:04 UTC

    What I would do is call SUPER::new->() (or whatever the constructor for your base class is) then manipulate the reference that comes out of that and then bless it into the child package. This is just off the top of my head but I would check here perltooc, which is class data in perl faq or here.

[followup] Re: OO: sharing data across inheritance
by skillet-thief (Friar) on Jun 03, 2004 at 12:52 UTC

    Thanks for all of the feedback.

    I ended up following just about everybody's advice and have ended up with a solution that seems to work. I gave up on inheritance and instead gave each Child (though no longer a child, per se) copy of the Parent objet.

    I was actually surprised to see that, from the child objet, I could still call the parent methods, by doing this :

    $child->{_parent_object}->method();
    Still not sure that is a good idea, but it seems to work for the time being.

    Thanks again

    s-t

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://359306]
Approved by Paulster2
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2019-05-21 08:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you enjoy 3D movies?



    Results (132 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!