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

Ok, so I have a class that I'm having a hard time designing properly with inheritance, and I feel confused dealing only with inheritance in OOP in other languages (C++, Java). My only resource isn't much help unfortunately, so I definitely need some Perl-y wisdom from some knowledgeable people right now.

My use model is to have a base class, develop multiple derived classes, piece together the final product as the sum of all of the inherited derived classes, then validate the sum in the final stage prior to executing it. This is being done to reduce maintenance on 30~75+ derived class modules.

So far my class looks something like the following:

#================= # Main require model::MAKE_BASIS; #================= # The following can live in model/MAKE_BASIS.pm package model::MAKE_BASIS; our @ISA= ( qw(Master_Classes::Make pm::Section), @ISA); use Data::Dumper; use pm::Section; $RULES = inheir_merge( exports => { # Environment variables to export at program's runtime. }, opts => { # A hash of options that get passed into a program. }, # Time limit for execution timeout => 12 ); #================= # The following lives in pm/Section.pm package pm::Section; use Data::Dumper; use qw(Exporter); our @ISA = qw(Exporter); our @EXPORT = qw(import inheir_merge); our @EXPORT_OK = qw(import inheir_merge); sub new { my $this = shift; my $class = ref($this) || $this; my $self = { # Empty definition just for example }; bless $self, $class; $self->validate(); } sub import { __PACKAGE__->export_to_level(1, qw(inheir_merge initialize)); } sub inheir_merge { my $class = ref(caller()) || caller(); my $self = {}; bless $self, $class; $self->SUPER::inheir_merge(@_) if($self->SUPER ne __PACKAGE__ +); }

However, when I try and run this piece of code I come up with a message stating:

"Undefined subroutine &model::MAKE_BASIS::inheir_merge"

I'm not sure why this is occurring though because I used use Exporter and all the symbols are being exported properly AFAIK.

Could anyone try and provide a suggestion to either redesign my class or approach the problem that could solve this particular issue?

I greatly appreciate your help.

-Garrett

Replies are listed 'Best First'.
Re: Dealing with design -- inheritance + exporting gone bad :(..
by Joost (Canon) on Jun 19, 2007 at 22:39 UTC
    That looks confusing, but so is your description of what it's supposed to do.

    It looks like you're exporting subroutines into derived classes. Which you shouldn't have to do, since derived classes already inherit their methods from the base class.

    Any way, if that's exactly what's in your code and this is one file then the immediate problem is you're use()ing "pm::Section" before it's defined, so pm::Section->import() is not called. Move pm::Section into it's own pm/Section.pm file.

    update: the above paragraph probably isn't right, since this code would abort when trying to load pm/Section.pm, unless you've also got that file but you're defining the rest of the package here.

    Also, since you're defining your own import() method, setting @EXPORT_OK & friends in pm::Section won't do a thing.

    Actually, everything in pm::Section::import and pm::Section::inheir_merge looks very suspicious.

      Q:Why are you exporting a method from a base class to an inheriting class? Normally you either export, or you inherit.

      A: It didn't seem like exporting was working properly (similar error came up as shown in the first post).

      Q: Why are you exporting your import() method?

      A: That was a bad idea -- I fixed that later after receiving your suggestion -- no one in my group honestly knows how to use export (just another guy and I know Perl, and it's somewhat limited to say the least in many areas), and it wasn't 100% clear in the Perldoc what to do with Exporter, until you clarified that point. :(..

      Q: Why are you even defining an import() method when the one you're inheriting from Exporter should work fine and yours does not? I.e. remove the import() method and fix the obvious syntax errors and you can use your inheir_merge() method from the use()ing package.

      A: I tried that and the call failed to do that properly before, but I'll try again..

      Q: Why are you creating an an object of the caller's class to call SUPER on when you can call caller()->SUPER::inheir_merge() directly?

      A: Right now I was just trying to get the call tree down properly so that I could verify that everything was working like it was supposed to. Next I was going to fill in the blanks in terms of merging the data elements together, instead of having all of the keyed hash items straight out replace one another.

      That's most likely not correct though now that I think about it because it will find the inheir_merge() subroutine at the bottom of the call stack, since I won't redefine it anywhere else, and thus it won't do what I want it to do.

      Q: And finally, what is all this supposed to do that you can't solve with straightforward (mutiple or single) inheritance?

      A: It's the merging part that's the cruxt and the issue in the whole problem. Instead of replacing a keyed hash element I want to append in some cases, search and replace arguments in some other cases, append to arrays in yet other cases, etc.

        Why are you exporting a method from a base class to an inheriting class? Normally you either export, or you inherit.

        Why are you exporting your import() method?

        Why are you even defining an import() method when the one you're inheriting from Exporter should work fine and yours does not? I.e. remove the import() method and fix the obvious syntax errors and you can use your inheir_merge() method from the use()ing package.

        Why are you creating an an object of the caller's class to to call SUPER on when you can call caller()->SUPER::inheir_merge() directly?

        And finally, what is all this supposed to do that you can't solve with straightforward (mutiple or single) inheritance?

        update: ah, I see a bit more. You'll probably just want to export properies. Since all of your properties seem to be class -based (i.e. no object-specific properties) you can for instance declare them as methods:

        Flies: Earthbound = 0; Machine: Metallic = 1; Warm-blooded: Blood = "warm"; Kryptonian: Weakness = "Kryptonite";
        package Base; # define default values sub earthbound { 0 } sub metallic { 0 } sub blood { "cold" } sub weakness { undef } # update 2: sub validate { my ($class) = @_; return ($class->blood eq 'warm' or ! $class->metallic); } # define 'mixins' - don't subclass these, # they'll export their properties when you use them package Flies; use base Exporter; our @EXPORT = qw(earthbound); sub earthbound { 1 } package Robot; use base Exporter; our @EXPORT = qw(metallic); sub metallic { 1 } # etc... package Superman; use base Base; use Flies; use Robot; # superman's very metallic.
Re: Dealing with design -- inheritance + exporting gone bad :(..
by shmem (Chancellor) on Jun 20, 2007 at 03:11 UTC
    However, when I try and run this piece of code I come up with a message stating:
    "Undefined subroutine &model::MAKE_BASIS::inheir_merge"

    Well, that's because this is a subroutine call:

    $RULES = inheir_merge( exports => { # Environment variables to export at program's runtime. }, opts => { # A hash of options that get passed into a program. }, # Time limit for execution timeout => 12 );

    and perl can't find a subroutine like

    sub inheir_merge { # subroutine code here }

    in the package model::MAKE_BASIS. Do you have that subroutine in a file you didn't post (model/MAKE_BASIS.pm) ? what is it supposed to do?

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

      I know -- unfortunately Exporter wasn't working as expected. My coworker and I found another method of solving the problem out of an O'Reilly book, but the problem is most simply solved by flattened and merging the objects, using a preset object name in the package.

      Sure, it means that errors may occur on occasion, but that's what I have error checking built into the classes for. The problem is better solved using the described method because this is a solution designed for ~20 some people, most who treat Perl like it's the plague.. I could go further into the discussion, but I don't think it's relevant to the topic anymore.

      Thanks for the attempt at helping me though. I learned a few things from you Joost :).