How do I inherit subroutines in Perl with 'use base'?

19,515

Solution 1

The C++ mechnics aren't much different than the Perl mechanics: To use inheritance, you need two classes: the base class and the inheriting class. But you don't have any descendent class.

You are also lacking a constructor. Unlike C++, Perl will not provide a default constructor for you.

Your base class contains a bad syntax error, so I guess you didn't try the code before posting.

Finally, as tsee already observed, you will have to let Perl know whether you want a function call or a method call.

What you really want would look something like this:

my $foo = TestDescendent->new();
$foo->main();


package TestBase;

sub new {
   my $class = shift;
   return bless {}, $class;
}

sub tbSub
{
   my ($self, $parm) = @_;
   print "\nTestBase: $parm\n";
}

package TestDescendent;
use base 'TestBase';

sub main {
    my $self = shift;
    $self->mySub( 1 );
    $self->tbSub( 2 );
    $self->mySub( 3 );
}

sub mySub
{
    my $self = shift;
    my $parm = shift;
    print "\nTester: $parm\n";
}

1;

Solution 2

You should have a look at using Moose which is a postmodern object system for Perl5. You will probably find it a lot easier to grasp than using standard Perl OO semantics... especially when coming from another OO language.

Here's a Moose version of your question....

package TestBase;
use Moose;

sub tbSub {
   my ($self, $parm) = @_;
   print "\nTestBase: $parm\n";
}


package TestDescendent;
use Moose;
extends 'TestBase';

sub main {
    my $self = shift;
    $self->mySub( 1 );
    $self->tbSub( 2 );
    $self->mySub( 3 );
}

sub mySub {
    my ($self, $parm) = @_;
    print "\nTester: $parm\n";
}


package main;
my $foo = TestDescendent->new();
$foo->main

The differences are....

  • Constructor automatically created for you &
  • Inheritance defined by "extends" command instead of "use base".

So this example only covers the tip of the Moose iceberg ;-)

Solution 3

As a sidenote, there is little good reason to use base rather than the newer use parent.

Solution 4

It seems to me, you are mixing up two things here: Object-Oriented and Procedural Perl. Perl OO is kind of "different" (as in not mainstream but workable).

Your TestBase.pm module seems to expect to be run as a Perl object (Perl oo-style), but your Perl script wants to access it as "normal" module. Perl doesn't work the way C++ does (as you realised) so you would have to construct your code differently. See Damian Conway's books for explanations (and smarter code than mine below).


Procedural:

#! /usr/bin/perl
#The module to inherit from

package TestBase;
  use strict;
  use warnings;

  use Exporter ();
  our @ISA         = qw (Exporter);
  our @EXPORT      = qw (tbSub);

#-------------------------------
sub tbSub
{
    my ($parm) = @_;
    print "\nTestBase: $parm\n";
}

1;

.

#! /usr/bin/perl
#The descendent class
use strict;
use warnings;

use TestBase; 
sub main;
sub mySub;

#-------------------------------
#Entry point...
main();

#---code------------------------
sub main
{

    mySub(1);
    tbSub(2);
    mySub(3);
}

#-------------------------------
sub mySub
{
    my $parm = shift;
    print "\nTester: $parm\n";
}

Perl OO

#! /usr/bin/perl
#The base class to inherit from

package TestBase;
  use strict;
  use warnings;

#-------------------------------
sub new { my $s={ };
    return bless $s;
}
sub tbSub
{
    my ($self,$parm) = @_;
    print "\nTestBase: $parm\n";
}

1;

.

#! /usr/bin/perl
#The descendent class
use strict;
use warnings;

use TestBase; 
sub main;
sub mySub;

#-------------------------------
#Entry point...
main();

#---code------------------------
sub main
{
    my $tb = TestBase->new();
    mySub(1);
    $tb->tbSub(2);
    mySub(3);
}

#-------------------------------
sub mySub
{
    my $parm = shift;
    print "\nTester: $parm\n";
}

Solution 5

Perl's inheritance inherits methods, not functions. That means you will have to call

main->tbSub(2);

However, what you really want is to inherit the method into a proper class:

package Derived;
use base "TestBase";

package main;
Derived->somemethod("foo");

Calling methods in the current package as functions won't pass in the $self or "this" object nor the class name magically. Internally,

Class->somemethod("foo")

essentially ends up being called as

Class::somemethod("Class", "foo")

internally. Of course, this assumes Class has a subroutine/method named "somemethod". If not, the superclasses of Class will be checked and if those don't have a method "somemethod" either, you'll get a fatal error. (Same logic applies for $obj->method("foo").)

Share:
19,515
slashmais
Author by

slashmais

Updated on June 15, 2022

Comments

  • slashmais
    slashmais about 2 years

    How do I apply 'use base' in Perl to inherit subs from some base module?

    I'm used to C++ inheritance mechanics, and all the sites I googled for this caused more confusion then help. I want to do something like the following:

    #! /usr/bin/perl
    #The base class to inherit from
    use strict;
    use warnings;
    
    package 'TestBase';
    
    #-------------------------------
    sub tbSub
    {
        my ($self, $parm) = @_;
        print "\nTestBase: $parm\n";
    }
    
    1;
    

    .

    #! /usr/bin/perl
    #The descendent class
    use strict;
    use warnings;
    
    use base qw(TestBase);
    sub main;
    sub mySub;
    
    #-------------------------------
    #Entry point...
    main();
    
    #---code------------------------
    sub main
    {
        mySub(1);
        tbSub(2);
        mySub(3);
    }
    
    #-------------------------------
    sub mySub
    {
        my $parm = shift;
        print "\nTester: $parm\n";
    }
    

    Perl complains/cannot find tbSub.