http://qs321.pair.com?node_id=836551

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

How can I inherit a method, in this example, test():
#!/usr/bin/perl -w use strict; { package One; sub test { my $x = pop; print "$x\n"; } } { package Two; use base "One"; sub new { my $self = {}; bless($self); } sub eg { test(pop); } } my $obj = new Two(); $obj->eg("hello");
I know "One->test()" will work, it just seems strange to me that I could then use $obj->test(), but not test() in Two's definition.

Replies are listed 'Best First'.
Re: Simple inheritance question
by ikegami (Patriarch) on Apr 23, 2010 at 16:51 UTC

    Perl has no idea it's suppose to call test as a method.

    The only difference between a function and a method is how the sub is called, or rather, how it expects to be called.

    test() # function Module::test() # function $obj->test() # virtual instance method $class->test() # static method

    Non-virtual instance methods can be approximated using

    test($obj) # From within the object that defines test(). -or- Class::test($obj) # From anywhere.

    I say "approximate", since it's doesn't check inheritance.

    And there's also this syntax:

    $obj->Class::test() $class->Class::test() $obj->SUPER::test() $class->SUPER::test()

    In this case, all of the following work:

    sub eg { $_[0]->test($_[1]); } sub eg { One::test(@_); } sub eg { Two->test($_[1]); } sub eg { One->test($_[1]); }

    Only the first really makes sense, though. And maybe the second one if you don't want test to be overridden by a child class of Two.

Re: Simple inheritance question
by jethro (Monsignor) on Apr 23, 2010 at 16:29 UTC
    If test() were included in Two's namespace, Two could not override it with its own test() if needed.

    UPDATE: You can use Exporter to add test to Two's namespace if you like. After all a class is just a package

      Yeah, that does it:
      #!/usr/bin/perl -w use strict; { package One; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(test); sub test { my $x = pop; print "$x\n"; } } { package Two; use base "One"; sub new { One->import; my $self = {}; bless($self); } sub eg { test(pop); } } my $obj = new Two(); $obj->eg("hello");
      Thanks all!
Re: Simple inheritance question
by webfiend (Vicar) on Apr 23, 2010 at 16:19 UTC

    The main problem here is that you don't have a constructor for package One, so there's nothing for package Two to inherit. There are a lot of other little things with the code (like the fact that test() is a simple sub rather than a method, for example) which suggest the Perl OO tutorial perltoot might be a good item for you to read for a handle on how objects are handled in Perl.

    Edit: I answered the wrong question and with an inaccurate answer. Then again, I learned something new about Perl and how it handles inheritance, so it wasn't a total loss.

      Adding a constructor to One does not make any difference. Would have been nice if you could have named those "little things" since I have already read the man page, and all of "Intermediate Perl" (the OO book).

      AFAICT it simply isn't possible to call a method from One in Two without using a class prefix. Simple confirmation of this (from someone who knows) will suffice, using One::test() instead of test() is fine, it just seems slightly silly, since One inherited Two's methods.
        Would have been nice if you could have named those "little things"

        That's a fair point. Here's a modified version of the code doing what I think you might have been trying to do. I'm also realizing I may have misread the question, but I've got momentum now. Might as well paste what I have.

        #!/usr/bin/perl # Use the warnings pragma rather than the -w flag use warnings; use strict; { package One; # Define a constructor for One sub new { my $class = shift; # Constructors need to know what class they +'re for my $self = {}; bless($self, $class); # Tell Perl what $self is being blessed +into } sub test { my $self = shift; # Is this an object method? Better grab $sel +f my $x = pop @_; # I usually shift from the argument list, but +whatever # Also, I like to be explicit about what I'm # popping/shifting from print "$x\n"; } } { package Two; use base "One"; # Two::new didn't add anything to One, so I removed it. sub eg { my $self = shift; # Is this an object method? Better grab $se +lf my $arg = pop @_; # pop() again? Okay, break it out and make +it explicit. $self->test($arg); # Is test() an object method? I'll use it a +s if it was. } } my $obj = new Two(); $obj->eg("hello");

        Edit: Incidentally, I think jethro has the solution you're looking for. I've become so used to making everything explicit by spelling out object or module connections that I didn't even think of Exporter.

Re: Simple inheritance question
by nvivek (Vicar) on Apr 24, 2010 at 09:34 UTC

    In the eg subroutine,you have to call the test subroutine by in the following two ways.

    $_[0]->test(pop); #Here $_[0] contains the class name. #first interpreter will check test is defined in Two or not. #If it isn't defined,then it will check the method in One package beca +use of use base function One::test(pop); #calling the test method using the class name One beca +use test isn't in Two's package workspace