Object-Oriented Perl: Inheritance, and why it's not Java

I’m quite a fan of both Java and Perl, for quite opposite reasons; Java is very strict, syntactically, and is rather good in collaborative environments as a result, where Perl is entirely the opposite of strict (even with use strict; in operation), and is therefore a delight to program in.

One thing they share is the ability to work with objects. However, this gives rise to an interesting difference: Java is object-oriented, where Perl is not.

In Java, you call a “function” by using its name, just like in any other language.

// declare the function
double square(int x){
   return x * x;
}


//somewhere else, we call it
double y = square(x);

Ditto, Perl:

# declare the sub
sub square(){
   my $x = shift;
   return $x * $x;
}

# somewhere else, we call it
my $y = square($x);

All very well, until we get into inheritance.

perl-oo-1
In Java, if the function “square” is declared in a superclass of the calling code, the above snippet will still work perfectly well; if we run double y = square(x); in code in class Banana, it will happily execute square() as if it were a local function.

Perl, on the other hand, is fundamentally a procedural language, so it assumes that function calls as shown above are internal to the current package. This means that if the sub “square” as shown above is in a superclass of the calling code, it won’t work.

This is where we have to _tell_ Perl that it’s using objects.

Firstly, some background. Inheritance in Perl is pretty easy: you create the inheriting package in the usual way, and you populate the @ISA array (pronounced “is-a”) with a list of packages to inherit, with the highest priority/affinity first. Yes, Perl supports multiple inheritance, which Java does not. As an example:

package 'Banana';
@ISA = ('Aardvark');

If package Banana contains the line of code my $y = square($x);, it will cause an error on execution, because Perl doesn’t know that square should be treated as an OO function, but rather it looks in the current scope for that function.

Now, if the calling code above is in a _different_ package, and contained an object reference to our package Banana in a variable $b, then we could get it to work by doing this:
$my $y = $b->square($x);

Interestingly, this will work whether square() is implemented in A or B. Go figure.

So, to get over this, we call the function via an object reference. In Perl, when an instance method is called (e.g. $b->square($x);), the first parameter to the function is the object reference. Conventionally, this is often written into a variable called $self.

If we need to call another function from that one, while retaining OO techniques, we use $self->otherfunction(). This solves our problem with inheritance, and is not a million miles removed from Java’s this keyword, although is far from implicit; remember, Java is fundamentally object-oriented, where Perl needs to be reminded.

Code samples:

package Aardvark;

sub square(){
    my($self, $x) = @_;
    return $x * $x;
}

package Banana;

use Aardvark;
our @ISA = ('Aardvark');


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

# test calling an inherited instance method
sub printstuff {
    my $self=shift;
    print $self->square(5.2) . "n";
}


package main;

use Banana;
my $b = Banana->new();

# see if square works when called from Banana
$b->printstuff();

# see if square works when called from here, via Banana
print $b->square(1.5) . "n";
Advertisement