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

This must be very common/standard OO machinery, but it seems that only at an extremely slow pace can I grasp object oriented concepts and techniques.

I would like to have a class, say MyClass each instance object of which holds some data, and having a method, say item really returning an object of another class, e.g. MyClass::Item. Now I want the latter to have access both to its specific data and to the instance data of the MyClass object.

I was thinking of a naive solution based on simply passing info about MyClass's specific instance to MyClass::Item 's constructor, a' la:

(example trimmed down to a bare minimum.)

#!/usr/bin/perl -l use strict; use warnings; package MyClass; sub new { my ($class, $data)=@_; bless { DATA => $data }, $class; } sub item { my $self=shift; MyClass::Item->new($self,@_); } package MyClass::Item; sub new { my ($class, $daddy, $data)=@_; bless { DADDY => $daddy, DATA => $data }, $class; } sub info { my $self=shift; "Generic data: ", $self->{DADDY}{DATA}, " - ", "This item's data: ", $self->{DATA}; } package main; my $c=MyClass->new('Foo'); my @items=map $c->item($_), qw/aa bb cc/; print $_->info for @items; __END__

However I strongly suspect that there may be better ways...

Replies are listed 'Best First'.
Re: Instance data inheritance?
by merlyn (Sage) on May 13, 2005 at 11:28 UTC
    You're probably looking for "prototypes" (not the Perl sense, but the rest of the world's sense) or "slot-based" objects. Perhaps Class::Prototyped would work for you? I have a brief introduction to them at one of my columns, and they're the basis for my CGI::Prototype, helping me to solve some of the odder problems with relative ease.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.


    update: To get you started, here's an example of your problem using Class::Prototyped:
    use Class::Prototyped; my $parent = Class::Prototyped->new( DATA => 'Daddy Data', info => sub { my $self = shift; print "Generic data: ", $self->reflect->class->DATA, "\n"; print "My data: ", $self->DATA, "\n"; } ); my @kids = map $parent->new(DATA => $_), qw(aa bb cc); for (@kids) { $_->info; }
Re: Instance data inheritance?
by tphyahoo (Vicar) on May 13, 2005 at 11:51 UTC
    This would be composition, not inheritance in the OO sense, would it not? (Warning: Still trying to wrap my head around OO myself...)
      Most probably, yes - I'm not really sure for I'm not familiar with the technical acceptation of composition as used here. In some sense, no. In fact I may well access such instance data through methods, and it would be fine for me to have
      package MyClass::Item; our @ISA=qw/MyClass/;
      But then again I'm not really sure whether it would be possible to access instance specific data this way and if so, which would be the "best way(TM)" to do so.

      Basically, in a real world example, I'd "simply" like to have the constructor (or some accessory method) of MyClass store some data into the instance objects, and I would like methods called on MyClass::Item objects to depend on that data.

Re: Instance data inheritance?
by tlm (Prior) on May 13, 2005 at 22:16 UTC

    I think merlyn's take on what you are trying to do is on target, but I suspect that the documentation for Class::Prototyped may be rough going for you if you are still finding your way around Perl objects. It is certainly rough going for me.

    Your solution is pretty common, for what I've seen.

    the lowliest monk

Re: Instance data inheritance?
by Anonymous Monk on May 13, 2005 at 16:29 UTC
    Don't worry! Your first try is good. Unless you need a snapshot of the (parent) data as the child is constructed, it is valid to simply include a ref to the parent. If you don't want to expose the parent data to the rest of the world but to the child only, you can construct a sub that extracts the needed data given a ref. The ref to this sub will be another argument to the constructor of the child.
Re: Instance data inheritance?
by herveus (Prior) on May 16, 2005 at 11:25 UTC
    Howdy!

    If you have a case where MyClass::Item ISA MyClass, then you can rebless the object into the subclass. I'm using that technique right now on a project.

    In my case, I have a set of fairly closely coupled classes (and that coupling is reasonable in this case). The parent class carries the data used all over the place and the subclasses carry more task specific data. As the object (and it could well be a Singleton) gets passed from one phase to another, it gets reblessed into the class that encapsulates the phase specific state and behavior.

    This may not be the best structure, but it has fallen out rather naturally as I grok this ball of mud I've inherited.

    In my case, I take care to capture the previous class and (effectively) localize the class change to the phase in question.

    yours,
    Michael
      In Smalltalk, rather than doing the equivalent of "rebless", a much more easy-to-understand metaphor is to have the object carry ("has a") its current "state" as an instance variable, so the data payload would remain constant, but things that you would have changed with "reblessing" are all delegated to an updated-as-necessary "partial brain".

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

      If you have a case where MyClass::Item ISA MyClass, then you can rebless the object into the subclass. I'm using that technique right now on a project.
      I must say that I had thought of using "real inheritance" by cloning the "parent instance" data (or some relevant portion of it) into the child objects - however it seeemed to me to be totally unacceptable in terms of data payload.

      Now that you point it out, reblessing doesn't seem to be affected by this downside, yet I'm slightly concerned about it, from the conceptual poin of view since it conveys the impression of including data into the "item" objects that really doesn't belong to them (but they must have access to it).

        Howdy!

        The objects are initially created as X, then serially reblessed into subclasses of X. Each subclass extends the state and behavior from there.

        yours,
        Michael