Inspired by my parents coming to visit at the end of the week, I thought I’d write about how Perl classes can have “parents” as well, from which they inherit methods. Although it might seem on the surface as though there’s more than one way to do it, these techniques all share the same underlying mechanism.
Where it all BEGINs: @ISA
Perl classes are just repurposed packages, i.e., a namespace for variables and subroutines. The two key differences are:
- Subroutines may expect either an object referenceor the name of a class as their first argument.
- When you call a method that isn’t defined in a class, Perl will search through the special
@ISAarrayin the package for the name of a class that has that method. (You can change the search order with themro(method resolution order) pragma.)
If you wanted to do everything by hand at the lowest level, you could make a subclass at compile time like this:
package Local::MyChildClass;
BEGIN { # don't do this:
require Local::MyParentClass;
push @ISA, 'Local::MyParentClass';
}
Don’t do that though, because we have…
baseand parent
In 1997 Perl 5.004_04 introducedthe basepragma (back when Perl used that kind of versioning scheme; in these days of semantic versioningwe’d call it version 5.4.4). It does the above BEGINblockin a single line:
use base 'Local::MyParentClass'; # don't do this unless you're also using fields
You might see use basein older code especially if it’s also using the fieldspragma. However, Perl developers discourageboth as the former silences certain module loading errorswhile the latter is at odds with the object-oriented programming principle of encapsulation.
So use parentinstead, which Perl has included since version 5.10.1in 2009:
use parent 'Local::MyParentClass';
A couple of years ago my Newfold Digitalcolleague David Oswaldcreated a fork of parent called parent::versionedthat supports specifying the lowest version for superclasses. You call it like this:
use parent::versioned ['Local::MyParentClass' => 1.23];
Within an OO system
There are dozens of object-oriented programming systemson CPANthat provide syntactic sugarand extra features to Perl’s minimal but flexible basics. Two of the more popular ones, Mooseand Moo, offer an extendskeyword that you should use instead of use parentso that your subclasses may take advantage of their features:
package Local::MyChildClass;
use Moo;
extends 'Local::MyParentClass';
Moose can also specify a required superclass version:
package Local::MyChildClass;
use Moose;
extends 'Local::MyParentClass' => {-version => 1.23};
Also, use the MooseX::NonMoosemodule when extending non-Moose classes, again so you get Moose features even though your methods are coming from somewhere else:
package Local::MyMooseClass;
use Moose;
use MooseX::NonMoose;
extends 'Local::MyPlainParentClass';
The experimental Object::Padmodule specifies a single superclass while defining the class name with an optional version. Per the author’s suggested file layout, including a required minimum version, it would look like:
use Object::Pad 0.41;
package Local::MyChildClass;
class Local::MyChildClass isa Local::MyParentClass 1.23;
Object::Pad and Corinna, its inspiration, are works in progress so this syntax isn’t set in stone. The latter’s designer Curtis “Ovid” Poe blogged earlier this weekabout considering a more self-consistent syntax.
Multiple inheritancevs. roles
To quote the Perl documentation, “multiple inheritance often indicates a design problem, but Perl always gives you enough rope to hang yourself with if you ask for it.” All the techniques described above except for Object::Pad support multiple inheritance by specifying a list of superclasses. For example:
package Local::MyChildClass;
use parent qw(Local::MyParentClass1 Local::MyParentClass2);
If you’re using roles instead of or on top of superclasses (I’ve seen both situations) and your OO system doesn’t support them on its own, you can use the Role::Tiny module, first by describing your role in one package and then consuming it in another:
package Local::DoesSomething;
use Role::Tiny;
...
1;
package Local::MyConsumer;
use Role::Tiny::With;
with 'Local::DoesSomething';
...
1;
Moo::Roleuses Role::Tiny under the hood and Moo can compose roles from either. The syntax for both Moo and Moose is similar:
package Local::DoesSomething;
use Moo::Role; # or "use Moose::Role;"
...
1;
package Local::MyConsumer;
use Moo; # or "use Moose;"
with 'Local::DoesSomething';
...
1;
Object::Pad specifies roles with the rolekeyword, and both classes and roles use doesto consume them:
use Object::Pad 0.56;
package Local::DoesSomething;
role Local::DoesSomething does Local::DoesSomethingElse;
...
1;
use Object::Pad 0.56;
package Local::MyConsumer;
class Local::MyConsumer does Local::DoesSomething;
...
1;
The previous caveatabout possible changes to this syntax applies.
Like parent, (sort of) like child
Of course, the whole point of inheritance or role consumption is so your child or consumer class can reuse functions and methods. Each of the techniques above has its ways of overriding that code, from the Perl built-in SUPERpseudo-classto Moose’s overrideand superkeywords, to Moose’sand Moo’smethod modifiers. (You can use the latter outside of Moo since it’s provided by Class::Method::Modifiers.)
I’ve written about choosing between overridingand modifying methodsbefore, and when it comes to Moose and Moo code I’m now on the side of using the aroundmethod modifierif a method needs to call an inherited or consumed method of the same name. Object::Pad doesn’t have method modifiers (yet), so classes that use it will have to satisfy themselves with SUPERin their methods with an :overrideattribute that will throw an error if a parent doesn’t also provide the same method.
The Parent Wrap
In the end, your choice of Perl OO systemwill determine how (or whether) you handle inheritance and may even be a deciding factor. Which would you choose? And more importantly, have I made my parents proud with this post?


