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

Dear Monks,

I'm still at a lost after reading a bit of Perl OO material and now I really need to ask for your guidance. I have multiple methods with the same name in an class hirearchy. How do I ensure the correct method is invoked base on the objects type?

Thanks!!!

Broken code...

#!/usr/bin/perl use strict; use warnings; use Animal; my $dog = Animal->new(); $dog->type("Dog"); my $cat = Animal->new(); $cat->type("Cat"); print $dog->speak; print $cat->speak; ------------------------------------------------------------------- package Animal; use Cat; use Dog; @ISA = qw(Cat Dog); use strict; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{TYPE} = undef; bless ($self, $class); return $self; } sub type { my $self = shift; if (@_) { $self->{TYPE} = shift } return $self->{TYPE}; } sub speak { my $self = shift; my $type = $self->{TYPE}; $self->$type::talk; } 1; ------------------------------------------------------------------- package Cat; use strict; sub speak { print "meow...\n"; } 1; ------------------------------------------------------------------- package Dog; use strict; sub speak { print "woof...\n"; } 1;

Replies are listed 'Best First'.
Re: OO & multiple inheritance.
by davorg (Chancellor) on Nov 18, 2004 at 09:30 UTC

    You have your inheritance the wrong way round. Cats and dogs are types of animal, so the Cat and Dog classes need to inherit from Animal - not the other way round.

    package Animal; sub new { my $class = shift; my $self = {}; bless ($self, $class); return $self; } 1; ------------------------------------------------------------------- package Cat; use strict; use Animal; our @ISA = qw(Animal); sub speak { print "meow...\n"; } 1; ------------------------------------------------------------------- package Dog; use strict; use Animal; our @ISA = qw(Animal); sub speak { print "woof...\n"; } 1; --------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; use Dog; use Cat; my $dog = Dog->new(); my $cat = Cat->new(); $dog->speak; $cat->speak;

    I've also removed the "ref($proto) || $proto" cargo-culting from your code. If you want people to be able to call your constructor as an object method as well as a class method then you should probably have another (object method) constructor called "clone" or "copy". It's generally considered bad practice to have one constructor that is used as both.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Howdy!

      I've also removed the "ref($proto) || $proto" cargo-culting from your code. If you want people to be able to call your constructor as an object method as well as a class method then you should probably have another (object method) constructor called "clone" or "copy". It's generally considered bad practice to have one constructor that is used as both.

      That paragraph is neeedlessly insulting, especially to someone who is manifestly new to Perl OO, if not OO in general. Further, it offers no pointers to more information on why "ref($proto) || $proto" is a bad thing, and makes an overly broad claim that it is. Without intending to divert this conversation down that path, I'll note that the question is not as settled as one would presume from the claim.

      yours,
      Michael

        ...is neeedlessly insulting...

        Actually, it didn't look insulting to me at all.
        I wonder why you aren't giving pointers to the matter, as you critcise their absence. I guess not everyone instantly understand what the both of you are talking about.
        I admit I don't do it either, but I know of this thread: ref($proto) - just say no!
        ...and I have my personal opinion on it too.

        Given the opintion expressed in that paragraph is debatable, it's still just one paragraph in a good node providing a complete answer to the OP's question.

        Cheerio, Sören

        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: OO & multiple inheritance.
by gaal (Parson) on Nov 18, 2004 at 08:58 UTC
    Method calls in Perl are what is called "virtual" in other languages. If an object is blessed to Dog, and you call $obj->speak(), Perl searches @INC starting from Dog's.

    Your constructor is already subclassable -- that's what your blessing to $class achieves -- so instead of calling Animal->new call Dog->new and Cat->new directly, and don't bother with the type; it'll happen automagically.

    (You can tell what kind of Animal you have by calling ref $obj on an instance.)

      (You can tell what kind of Animal you have by calling ref $obj on an instance.)
      But don't do that, as it will break the "null subclass test". Instead, use "isa" or "can" to test inheritance or capability. The code:
      if (ref $this eq "Some::Class::Of::Interest") { ... }
      is almost always wrong, and is red-flagged in my code reviews.

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

        Quick thought for Perl6: ref() could return an any() junction created with the @ISA for the class. Then ref() and isa() would be functionally equivilent.

        "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

        Yes, you are right, of course.
Re: OO & multiple inheritance.
by brian_d_foy (Abbot) on Nov 18, 2004 at 19:06 UTC

    To see this example worked out in detail, check out the Perl Barnyard Object-Oriented tutorial (perlboot), which Randal wrote but failed to mention in his reply. :)

    Somehow this is now called the "Beginner's Object Oriented Tutorial", but that's not how it started. I was there when it happened, then someone wussed out on the name.

    --
    brian d foy <bdfoy@cpan.org>
Re: OO & multiple inheritance.
by ikegami (Patriarch) on Nov 18, 2004 at 16:23 UTC

    Like someone already pointed out, you have inheritance backwards. Would you say a "Cat is a type of Animal" or "Animal is a type of Cat"? @ISA is used to express this is a relationship.

    Another tip is that you should never have to store something class-specific in a parent class. For example, TYPE should no more in Animal than SOUND. It's better to override a method (class function), like you did with speak.

    I also agree with not using ref($proto). It's a legacy from languages which are unable to name their constructors. In Perl, if you need a copy constructor, go ahead and call it copy.