Multiple ways to inheritance in Perl

Inspired by my par­ents com­ing to vis­it at the end of the week, I thought I’d write about how Perl class­es can have ​“par­ents” as well, from which they inher­it meth­ods. Although it might seem on the sur­face as though there’s more than one way to do it, these tech­niques all share the same under­ly­ing mechanism.

Where it all BEGINs: @ISA

Perl class­es are just repur­posed packages, i.e., a name­space for vari­ables and sub­rou­tines. The two key dif­fer­ences are:

If you want­ed to do every­thing by hand at the low­est lev­el, you could make a sub­class at com­pile 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 intro­ducedthe baseprag­ma (back when Perl used that kind of ver­sion­ing scheme; in these days of seman­tic ver­sion­ingwe’d call it ver­sion 5.4.4). It does the above BEGINblockin a sin­gle line:

use base 'Local::MyParentClass'; # don't do this unless you're also using fields

You might see use basein old­er code espe­cial­ly if it’s also using the fieldsprag­ma. However, Perl devel­op­ers dis­cour­ageboth as the for­mer silences cer­tain mod­ule load­ing errorswhile the lat­ter is at odds with the object-​oriented pro­gram­ming prin­ci­ple of encap­su­la­tion.

So use parentinstead, which Perl has includ­ed since ver­sion 5.10.1in 2009:

use parent 'Local::MyParentClass';

A cou­ple of years ago my Newfold Digitalcol­league David Oswaldcre­at­ed a fork of par­ent called parent::versionedthat sup­ports spec­i­fy­ing the low­est ver­sion for super­class­es. You call it like this:

use parent::versioned ['Local::MyParentClass' => 1.23];

Within an OO system

There are dozens of object-​oriented pro­gram­ming sys­temson CPANthat pro­vide syn­tac­tic sug­arand extra fea­tures to Perl’s min­i­mal but flex­i­ble basics. Two of the more pop­u­lar ones, Mooseand Moo, offer an extendskey­word that you should use instead of use parentso that your sub­class­es may take advan­tage of their features:

package Local::MyChildClass;
use Moo;
extends 'Local::MyParentClass';

Moose can also spec­i­fy a required super­class version:

package Local::MyChildClass;
use Moose;
extends 'Local::MyParentClass' => {-version => 1.23};

Also, use the MooseX::NonMoosemod­ule when extend­ing non-​Moose class­es, again so you get Moose fea­tures even though your meth­ods are com­ing from some­where else:

package Local::MyMooseClass;
use Moose;
use MooseX::NonMoose;
extends 'Local::MyPlainParentClass';

The exper­i­men­tal Object::Padmod­ule spec­i­fies a sin­gle super­class while defin­ing the class name with an option­al ver­sion. Per the author’s sug­gest­ed file lay­out, includ­ing a required min­i­mum ver­sion, 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 inspi­ra­tion, are works in progress so this syn­tax isn’t set in stone. The latter’s design­er Curtis ​“Ovid” Poe blogged ear­li­er this weekabout con­sid­er­ing a more self-​consistent syntax.

Multiple inheritancevs. roles

To quote the Perl doc­u­men­ta­tion, ​“mul­ti­ple inher­i­tance often indi­cates a design prob­lem, but Perl always gives you enough rope to hang your­self with if you ask for it.” All the tech­niques described above except for Object::Pad sup­port mul­ti­ple inher­i­tance by spec­i­fy­ing a list of super­class­es. For example:

package Local::MyChildClass;
use parent qw(Local::MyParentClass1 Local::MyParentClass2);

If you’re using roles instead of or on top of super­class­es (I’ve seen both sit­u­a­tions) and your OO sys­tem doesn’t sup­port them on its own, you can use the Role::Tiny mod­ule, first by describ­ing your role in one pack­age and then con­sum­ing 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 com­pose roles from either. The syn­tax 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 spec­i­fies roles with the rolekey­word, and both class­es and roles use doesto con­sume 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 pre­vi­ous caveatabout pos­si­ble changes to this syn­tax applies.

Like parent, (sort of) like child

Of course, the whole point of inher­i­tance or role con­sump­tion is so your child or con­sumer class can reuse func­tions and meth­ods. Each of the tech­niques above has its ways of over­rid­ing that code, from the Perl built-​in SUPERpseudo-​classto Moose’s overrideand superkey­words, to Moose’sand Moo’smethod mod­i­fiers. (You can use the lat­ter out­side of Moo since it’s pro­vid­ed by Class::Method::Modifiers.)

I’ve writ­ten about choos­ing between over­rid­ingand mod­i­fy­ing meth­odsbefore, and when it comes to Moose and Moo code I’m now on the side of using the aroundmethod mod­i­fi­erif a method needs to call an inher­it­ed or con­sumed method of the same name. Object::Pad doesn’t have method mod­i­fiers (yet), so classes that use it will have to sat­is­fy them­selves with SUPERin their methods with an :overrideattribute that will throw an error if a par­ent doesn’t also pro­vide the same method.

The Parent Wrap

In the end, your choice of Perl OO sys­temwill deter­mine how (or whether) you han­dle inher­i­tance and may even be a decid­ing fac­tor. Which would you choose? And more impor­tant­ly, have I made my par­ents proud with this post?


Discover more from The Phoenix Trap

Subscribe to get the latest posts sent to your email.

Mark Gardner Avatar

Hi, I’m Mark.

Hi, I’m Mark Gard­ner, and this is my personal blog. I show software developers how to level up by building production-ready things that work. Clear code, real projects, lessons learned.

Comments

One response to “Multiple ways to inheritance in Perl”

  1. […] Multiple ways to inher­i­tance in Perl […]

Your post must include a link to this post.

How does this work?
Write a response on your own website and include a link to this post. Then submit your response’s URL here. Your response may appear here after moderation. To update or remove it, edit or delete your original post and submit the same URL again. Learn more about Webmentions.