Friday, December 17, 2021, marked the thirty-​fourth birth­day of the Perl pro­gram­ming lan­guage, and coin­ci­den­tal­ly this year saw the release of ver­sion 5.34. There are plen­ty of Perl devel­op­ers out there who haven’t kept up with recent (and not-​so-​recent) improve­ments to the lan­guage and its ecosys­tem, so I thought I might list a batch. (You may have seen some of these before in May’s post Perl can do that now!”)

The feature pragma

Perl v5.10 was released in December 2007, and with it came feature, a way of enabling new syn­tax with­out break­ing back­ward com­pat­i­bil­i­ty. You can enable indi­vid­ual fea­tures by name (e.g., use feature qw(say fc); for the say and fc key­words), or by using a fea­ture bun­dle based on the Perl ver­sion that intro­duced them. For exam­ple, the following:

use feature ':5.34';

…gives you the equiv­a­lent of:

use feature qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings);

Boy, that’s a mouth­ful. Feature bun­dles are good. The cor­re­spond­ing bun­dle also gets implic­it­ly loaded if you spec­i­fy a min­i­mum required Perl ver­sion, e.g., with use v5.32;. If you use v5.12; or high­er, strict mode is enabled for free. So just say:

use v5.34;

And last­ly, one-​liners can use the -E switch instead of -e to enable all fea­tures for that ver­sion of Perl, so you can say the fol­low­ing on the com­mand line:

perl -E 'say "Hello world!"'

Instead of:

perl -e 'print "Hello world!\n"'

Which is great when you’re try­ing to save some typing.

The experimental pragma

Sometimes new Perl fea­tures need to be dri­ven a cou­ple of releas­es around the block before their behav­ior set­tles. Those exper­i­ments are doc­u­ment­ed in the per­l­ex­per­i­ment page, and usu­al­ly, you need both a use feature (see above) and no warnings state­ment to safe­ly enable them. Or you can sim­ply pass a list to use experimental of the fea­tures you want, e.g.:

use experimental qw(isa postderef signatures);

Ever-​expanding warnings categories

March 2000 saw the release of Perl 5.6, and with it, the expan­sion of the -w command-​line switch to a sys­tem of fine-​grained con­trols for warn­ing against dubi­ous con­structs” that can be turned on and off depend­ing on the lex­i­cal scope. What start­ed as 26 main and 20 sub­cat­e­gories has expand­ed into 31 main and 43 sub­cat­e­gories, includ­ing warn­ings for the afore­men­tioned exper­i­men­tal features.

As the rel­e­vant Perl::Critic pol­i­cy says, Using warn­ings, and pay­ing atten­tion to what they say, is prob­a­bly the sin­gle most effec­tive way to improve the qual­i­ty of your code.” If you must vio­late warn­ings (per­haps because you’re reha­bil­i­tat­ing some lega­cy code), you can iso­late such vio­la­tions to a small scope and indi­vid­ual cat­e­gories. Check out the stric­tures mod­ule on CPAN if you’d like to go fur­ther and make a safe sub­set of these cat­e­gories fatal dur­ing development.

Document other recently-​introduced syntax with Syntax::Construct

Not every new bit of Perl syn­tax is enabled with a feature guard. For the rest, there’s E. Choroba’s Syntax::Construct mod­ule on CPAN. Rather than hav­ing to remem­ber which ver­sion of Perl intro­duced what, Syntax::Construct lets you declare only what you use and pro­vides a help­ful error mes­sage if some­one tries to run your code on an old­er unsup­port­ed ver­sion. Between it and the feature prag­ma, you can pre­vent many head-​scratching moments and give your users a chance to either upgrade or workaround.

Make built-​in functions throw exceptions with autodie

Many of Perl’s built-​in func­tions only return false on fail­ure, requir­ing the devel­op­er to check every time whether a file can be opened or a system com­mand exe­cut­ed. The lex­i­cal autodie prag­ma replaces them with ver­sions that raise an excep­tion with an object that can be inter­ro­gat­ed for fur­ther details. No mat­ter how many func­tions or meth­ods deep a prob­lem occurs, you can choose to catch it and respond appro­pri­ate­ly. This leads us to…

try/​catch exception handling and Feature::Compat::Try

This year’s Perl v5.34 release intro­duced exper­i­men­tal try/​catch syn­tax for excep­tion han­dling that should look more famil­iar to users of oth­er lan­guages while han­dling the issues sur­round­ing using block eval and test­ing of the spe­cial [email protected] vari­able. If you need to remain com­pat­i­ble with old­er ver­sions of Perl (back to v5.14), just use the Feature::Compat::Try mod­ule from CPAN to auto­mat­i­cal­ly select either v5.34’s native try/​catch or a sub­set of the func­tion­al­i­ty pro­vid­ed by Syntax::Keyword::Try.

Pluggable keywords

The above­men­tioned Syntax::Keyword::Try was made pos­si­ble by the intro­duc­tion of a plug­gable key­word mech­a­nism in 2010’s Perl v5.12. So was the Future::AsyncAwait asyn­chro­nous pro­gram­ming library and the Object::Pad test­bed for new object-​oriented Perl syn­tax. If you’re handy with C and Perl’s XS glue lan­guage, check out Paul LeoNerd” Evans’ XS::Parse::Keyword mod­ule to get a leg up on devel­op­ing your own syn­tax module.

Define packages with versions and blocks

Perl v5.12 also helped reduce clut­ter by enabling a package name­space dec­la­ra­tion to also include a ver­sion num­ber, instead of requir­ing a sep­a­rate our $VERSION = ...; v5.14 fur­ther refined packages to be spec­i­fied in code blocks, so a name­space dec­la­ra­tion can be the same as a lex­i­cal scope. Putting the two togeth­er gives you:

package Local::NewHotness v1.2.3 {
    ...
}

Instead of:

{
    package Local::OldAndBusted;
    use version 0.77; our $VERSION = version->declare("v1.2.3");
    ...
}

I know which I’d rather do. (Though you may want to also use Syntax::Construct qw(package-version package-block); to help along with old­er instal­la­tions as described above.)

The // defined-​or operator

This is an easy win from Perl v5.10:

defined $foo ? $foo : $bar  # replace this
$foo // $bar                # with this

And:

$foo = $bar unless defined $foo  # replace this
$foo //= $bar                    # with this

Perfect for assign­ing defaults to variables.

state variables only initialize once

Speaking of vari­ables, ever want one to keep its old val­ue the next time a scope is entered, like in a sub? Declare it with state instead of my. Before Perl v5.10, you need­ed to use a clo­sure instead.

Save some typing with say

Perl v5.10’s bumper crop of enhance­ments also includ­ed the say func­tion, which han­dles the com­mon use case of printing a string or list of strings with a new­line. It’s less noise in your code and saves you four char­ac­ters. What’s not to love?

Note unimplemented code with ...

The ... ellip­sis state­ment (col­lo­qui­al­ly yada-​yada”) gives you an easy place­hold­er for yet-​to-​be-​implemented code. It pars­es OK but will throw an excep­tion if exe­cut­ed. Hopefully, your test cov­er­age (or at least sta­t­ic analy­sis) will catch it before your users do.

Loop and enumerate arrays with each, keys, and values

The each, keys, and values func­tions have always been able to oper­ate on hash­es. Perl v5.12 and above make them work on arrays, too. The lat­ter two are main­ly for con­sis­ten­cy, but you can use each to iter­ate over an array’s indices and val­ues at the same time:

while (my ($index, $value) = each @array) {
    ...
}

This can be prob­lem­at­ic in non-​trivial loops, but I’ve found it help­ful in quick scripts and one-liners.

delete local hash (and array) entries

Ever need­ed to delete an entry from a hash (e.g, an envi­ron­ment vari­able from %ENV or a sig­nal han­dler from %SIG) just inside a block? Perl v5.12 lets you do that with delete local.

Paired hash slices

Jumping for­ward to 2014’s Perl v5.20, the new %foo{'bar', 'baz'} syn­tax enables you to slice a sub­set of a hash with its keys and val­ues intact. Very help­ful for cherry-​picking or aggre­gat­ing many hash­es into one. For example:

my %args = (
    verbose => 1,
    name    => 'Mark',
    extra   => 'pizza',
);
# don't frob the pizza
$my_object->frob( %args{ qw(verbose name) };

Paired array slices

Not to be left out, you can also slice arrays in the same way, in this case return­ing indices and values:

my @letters = 'a' .. 'z';
my @subset_kv = %letters[16, 5, 18, 12];
# @subset_kv is now (16, 'p', 5, 'e', 18, 'r', 12, 'l')

More readable dereferencing

Perl v5.20 intro­duced and v5.24 de-​experimentalized a more read­able post­fix deref­er­enc­ing syn­tax for nav­i­gat­ing nest­ed data struc­tures. Instead of using {braces} or smoosh­ing sig­ils to the left of iden­ti­fiers, you can use a post­fixed sigil-and-star:

push @$array_ref,    1, 2, 3;  # noisy
push @{$array_ref},  1, 2, 3;  # a little easier
push $array_ref->@*, 1, 2, 3;  # read from left to right

So much of web devel­op­ment is sling­ing around and pick­ing apart com­pli­cat­ed data struc­tures via JSON, so I wel­come any­thing like this to reduce the cog­ni­tive load.

when as a statement modifier

Starting in Perl v5.12, you can use the exper­i­men­tal switch fea­tures when key­word as a post­fix mod­i­fi­er. For example:

for ($foo) {
    $a =  1 when /^abc/;
    $a = 42 when /^dna/;
    ...
}

But I don’t rec­om­mend when, given, or givens smart­match oper­a­tions as they were ret­conned as exper­i­ments in 2013’s Perl v5.18 and have remained so due to their tricky behav­ior. I wrote about some alter­na­tives using sta­ble syn­tax back in February.

Simple class inheritance with use parent

Sometimes in old­er object-​oriented Perl code, you’ll see use base as a prag­ma to estab­lish inher­i­tance from anoth­er class. Older still is the direct manip­u­la­tion of the package’s spe­cial @ISA array. In most cas­es, both should be avoid­ed in favor of use parent, which was added to core in Perl v5.10.1.

Mind you, if you’re fol­low­ing the Perl object-​oriented tutorial’s advice and have select­ed an OO sys­tem from CPAN, use its sub­class­ing mech­a­nism if it has one. Moose, Moo, and Class::Accessor’s antlers” mode all pro­vide an extends func­tion; Object::Pad pro­vides an :isa attribute on its class key­word.

Test for class membership with the isa operator

As an alter­na­tive to the isa() method pro­vid­ed to all Perl objects, Perl v5.32 intro­duced the exper­i­men­tal isa infix oper­a­tor:

$my_object->isa('Local::MyClass')
# or
$my_object isa Local::MyClass

The lat­ter can take either a bare­word class name or string expres­sion, but more impor­tant­ly, it’s safer as it also returns false if the left argu­ment is unde­fined or isn’t a blessed object ref­er­ence. The old­er isa() method will throw an excep­tion in the for­mer case and might return true if called as a class method when $my_object is actu­al­ly a string of a class name that’s the same as or inher­its from isa()s argu­ment.

Lexical subroutines

Introduced in Perl v5.18 and de-​experimentalized in 2017’s Perl v5.26, you can now pre­cede sub dec­la­ra­tions with my, state, or our. One use of the first two is tru­ly pri­vate func­tions and meth­ods, as described in this 2018 Dave Jacoby blog and as part of Neil Bowers’ 2014 sur­vey of pri­vate func­tion techniques.

Subroutine signatures

I’ve writ­ten and pre­sent­ed exten­sive­ly about sig­na­tures and alter­na­tives over the past year, so I won’t repeat that here. I’ll just add that the Perl 5 Porters devel­op­ment mail­ing list has been mak­ing a con­cert­ed effort over the past month to hash out the remain­ing issues towards ren­der­ing this fea­ture non-​experimental. The pop­u­lar Mojolicious real-​time web frame­work also pro­vides a short­cut for enabling sig­na­tures and uses them exten­sive­ly in examples.

Indented here-​documents with <<~

Perl has had shell-​style here-​document” syn­tax for embed­ding multi-​line strings of quot­ed text for a long time. Starting with Perl v5.26, you can pre­cede the delim­it­ing string with a ~ char­ac­ter and Perl will both allow the end­ing delim­iter to be indent­ed as well as strip inden­ta­tion from the embed­ded text. This allows for much more read­able embed­ded code such as runs of HTML and SQL. For example:

if ($do_query) {
    my $rows_deleted = $dbh->do(<<~'END_SQL', undef, 42);
      DELETE FROM table
      WHERE status = ?
      END_SQL
    say "$rows_deleted rows were deleted."; 
}

More readable chained comparisons

When I learned math in school, my teach­ers and text­books would often describe mul­ti­ple com­par­isons and inequal­i­ties as a sin­gle expres­sion. Unfortunately, when it came time to learn pro­gram­ming every com­put­er lan­guage I saw required them to be bro­ken up with a series of and (or &&) oper­a­tors. With Perl v5.32, this is no more:

if ( $x < $y && $y <= $z ) { ... }  # old way
if ( $x < $y <= $z )       { ... }  # new way

It’s more con­cise, less noisy, and more like what reg­u­lar math looks like.

Self-​documenting named regular expression captures

Perl’s expres­sive reg­u­lar expres­sion match­ing and text-​processing prowess are leg­endary, although overuse and poor use of read­abil­i­ty enhance­ments often turn peo­ple away from them (and Perl in gen­er­al). We often use reg­ex­ps for extract­ing data from a matched pat­tern. For example:

if ( /Time: (..):(..):(..)/ ) {  # parse out values
    say "$1 hours, $2 minutes, $3 seconds";
}

Named cap­ture groups, intro­duced in Perl v5.10, make both the pat­tern more obvi­ous and retrieval of its data less cryptic:

if ( /Time: (?<hours>..):(?<minutes>..):(?<seconds>..)/ ) {
    say "$+{hours} hours, $+{minutes} minutes, $+{seconds} seconds";
}

More readable regexp character classes

The /x reg­u­lar expres­sion mod­i­fi­er already enables bet­ter read­abil­i­ty by telling the pars­er to ignore most white­space, allow­ing you to break up com­pli­cat­ed pat­terns into spaced-​out groups and mul­ti­ple lines with code com­ments. With Perl v5.26 you can spec­i­fy /xx to also ignore spaces and tabs inside [brack­et­ed] char­ac­ter class­es, turn­ing this:

/[d-eg-i3-7]/
/[[email protected]"#$%^&*()=?<>']/

…into this:

/ [d-e g-i 3-7]/xx
/[ ! @ " # $ % ^ & * () = ? <> ' ]/xx

Set default regexp flags with the re pragma

Beginning with Perl v5.14, writ­ing use re '/xms'; (or any com­bi­na­tion of reg­u­lar expres­sion mod­i­fi­er flags) will turn on those flags until the end of that lex­i­cal scope, sav­ing you the trou­ble of remem­ber­ing them every time.

Non-​destructive substitution with s///r and tr///r

The s/// sub­sti­tu­tion and tr/// translit­er­a­tion oper­a­tors typ­i­cal­ly change their input direct­ly, often in con­junc­tion with the =~ bind­ing oper­a­tor:

s/foo/bar/;  # changes the first foo to bar in $_
$baz =~ s/foo/bar/;  # the same but in $baz

But what if you want to leave the orig­i­nal untouched, such as when pro­cess­ing an array of strings with a map? With Perl v5.14 and above, add the /r flag, which makes the sub­sti­tu­tion on a copy and returns the result:

my @changed = map { s/foo/bar/r } @original;

Unicode case-​folding with fc for better string comparisons

Unicode and char­ac­ter encod­ing in gen­er­al are com­pli­cat­ed beasts. Perl has han­dled Unicode since v5.6 and has kept pace with fix­es and sup­port for updat­ed stan­dards in the inter­ven­ing decades. If you need to test if two strings are equal regard­less of case, use the fc func­tion intro­duced in Perl v5.16.

Safer processing of file arguments with <<>>

The <> null file­han­dle or dia­mond oper­a­tor” is often used in while loops to process input per line com­ing either from stan­dard input (e.g., piped from anoth­er pro­gram) or from a list of files on the com­mand line. Unfortunately, it uses a form of Perl’s open func­tion that inter­prets spe­cial char­ac­ters such as pipes (|) that would allow it to inse­cure­ly run exter­nal com­mands. Using the <<>> dou­ble dia­mond” oper­a­tor intro­duced in Perl v5.22 forces open to treat all command-​line argu­ments as file names only. For old­er Perls, the per­lop doc­u­men­ta­tion rec­om­mends the ARGV::readonly CPAN mod­ule.

Safer loading of Perl libraries and modules from @INC

Perl v5.26 removed the abil­i­ty for all pro­grams to load mod­ules by default from the cur­rent direc­to­ry, clos­ing a secu­ri­ty vul­ner­a­bil­i­ty orig­i­nal­ly iden­ti­fied and fixed as CVE-​2016 – 1238 in pre­vi­ous ver­sions’ includ­ed scripts. If your code relied on this unsafe behav­ior, the v5.26 release notes include steps on how to adapt.

HTTP::Tiny simple HTTP/1.1 client included

To boot­strap access to CPAN on the web in the pos­si­ble absence of exter­nal tools like curl or wget, Perl v5.14 began includ­ing the HTTP::Tiny mod­ule. You can also use it in your pro­grams if you need a sim­ple web client with no dependencies.

Test2: The next generation of Perl testing frameworks

Forked and refac­tored from the ven­er­a­ble Test::Builder (the basis for the Test::More library that many are famil­iar with), Test2 was includ­ed in the core mod­ule library begin­ning with Perl v5.26. I’ve exper­i­ment­ed recent­ly with using the Test2::Suite CPAN library instead of Test::More and it looks pret­ty good. I’m also intrigued by Test2::Harness’ sup­port for thread­ing, fork­ing, and pre­load­ing mod­ules to reduce test run times.

Task::Kensho: Where to start for recommended Perl modules

This last item may not be includ­ed when you install Perl, but it’s where I turn for a col­lec­tion of well-​regarded CPAN mod­ules for accom­plish­ing a wide vari­ety of com­mon tasks span­ning from asyn­chro­nous pro­gram­ming to XML. Use it as a start­ing point or inter­ac­tive­ly select the mix of libraries appro­pri­ate to your project.


And there you have it: a selec­tion of 34 fea­tures, enhance­ments, and improve­ments for the first 34 years of Perl. What’s your favorite? Did I miss any­thing? Let me know in the comments.

chocolate bar and sugar cubes on a hand
What about My::Favorite::Module?

I men­tioned at the Ephemeral Miniconf last month that as soon as I write about one Perl mod­ule (or five), some­one inevitably brings up anoth­er (or sev­en) I’ve missed. And of course, it hap­pened again last week: no soon­er had I writ­ten in pass­ing that I was using Exception::Class than the denizens of the Libera Chat IRC #perl chan­nel insist­ed I should use Throwable instead for defin­ing my excep­tions. (I’ve already blogged about var­i­ous ways of catch­ing excep­tions.)

Why Throwable? Aside from Exception::Class’s author rec­om­mend­ing it over his own work due to a nicer, more mod­ern inter­face,” Throwable is a Moo role, so it’s com­pos­able into class­es along with oth­er roles instead of muck­ing about with mul­ti­ple inher­i­tance. This means that if your excep­tions need to do some­thing reusable in your appli­ca­tion like log­ging, you can also con­sume a role that does that and not have so much dupli­cate code. (No, I’m not going to pick a favorite log­ging mod­ule; I’ll prob­a­bly get that wrong too.)

However, since Throwable is a role instead of a class, I would have to define sev­er­al addi­tion­al packages in my tiny mod­uli­no script from last week, one for each excep­tion class I want. The beau­ty of Exception::Class is its sim­ple declar­a­tive nature: just use it and pass a list of desired class names along with options for attrib­ut­es and what­not. What’s need­ed for sim­ple use cas­es like mine is a declar­a­tive syn­tax for defin­ing sev­er­al excep­tion class­es with­out the noise of mul­ti­ple packages.

Enter Throwable::SugarFactory, a mod­ule that enables you to do just that by adding an exception func­tion for declar­ing excep­tion class­es. (There’s also the similarly-​named Throwable::Factory; see the above dis­cus­sion about nev­er being able to cov­er everybody’s favorites.) The exception func­tion takes three argu­ments: the name of the desired excep­tion class as a string, a descrip­tion, and an option­al list of instruc­tions Moo uses to build the class. It might look some­thing like this:

package Local::My::Exceptions;
use Throwable::SugarFactory;

exception GenericError  => 'something bad happened';
exception DetailedError => 'something specific happened' =>
  ( has => [ message => ( is => 'ro' ) ] );

1;

Throwable::SugarFactory takes care of cre­at­ing con­struc­tor func­tions in Perl-​style snake_case as well as func­tions for detect­ing what kind of excep­tion is being caught, so you can use your new excep­tion library like this:

#!/usr/bin/env perl

use experimental qw(isa);
use Feature::Compat::Try;
use JSON::MaybeXS;
use Local::My::Exceptions;

try {
    die generic_error();
}
catch ($e) {
    warn 'whoops!';
}

try {
    die detailed_error( message => 'you got me' );
}
catch ($e) {
    die encode_json( $e->to_hash )
      if $e isa DetailedError and defined $e->message;
    $e->throw if $e->does('Throwable');
    die $e;
}

The above also demon­strates a cou­ple of oth­er Throwable::SugarFactory fea­tures. First, you get a to_hash method that returns a hash ref­er­ence of all excep­tion data, suit­able for seri­al­iz­ing to JSON. Second, you get all of Throwable’s meth­ods, includ­ing throw for re-​throwing exceptions. 

So where does this leave last week’s FOAAS.com mod­uli­no client demon­stra­tion of object mock­ing tests? With a lit­tle bit of rewrit­ing to define and then use our sweet­er excep­tion library, it looks like this. You can review for a descrip­tion of the rest of its workings.

#!/usr/bin/env perl

package Local::CallFOAAS::Exceptions;
use Throwable::SugarFactory;

BEGIN {
    exception NoMethodError =>
      'no matching WebService::FOAAS method' =>
      ( has => [ method => ( is => 'ro' ) ] );
    exception ServiceError =>
      'error from WebService::FOAAS' =>
      ( has => [ message => ( is => 'ro' ) ] );
}

package Local::CallFOAAS;  # this is a modulino
use Test2::V0;             # enables strict, warnings, utf8

# declare all the new stuff we're using
use feature qw(say state);
use experimental qw(isa postderef signatures);
use Feature::Compat::Try;
use Syntax::Construct qw(non-destructive-substitution);

use WebService::FOAAS ();
use Package::Stash;
BEGIN { Local::CallFOAAS::Exceptions->import() }

my $foaas = Package::Stash->new('WebService::FOAAS');

my $run_as =
    !!$ENV{CPANTEST}       ? 'test'
  : !defined scalar caller ? 'run'
  :                          undef;
__PACKAGE__->$run_as(@ARGV) if defined $run_as;

sub run ( $class, @args ) {
    try { say $class->call_method(@args) }
    catch ($e) {
        die 'No method ', $e->method, "\n"
          if $e isa NoMethodError;
        die 'Service error: ', $e->message, "\n"
          if $e isa ServiceError;
        die "$e\n";
    }
    return;
}

# Utilities

sub methods ($) {
    state @methods = sort map s/^foaas_(.+)/$1/r,
      grep /^foaas_/, $foaas->list_all_symbols('CODE');
    return @methods;
}

sub call_method ( $class, $method = '', @args ) {
    state %methods = map { $_ => 1 } $class->methods();
    die no_method_error( method => $method )
      unless $methods{$method};
    return do {
        try { $foaas->get_symbol("&$method")->(@args) }
        catch ($e) { die service_error( message => $e ) }
    };
}

# Testing

sub test ( $class, @ ) {
    state $stash = Package::Stash->new($class);
    state @tests = sort grep /^_test_/,
      $stash->list_all_symbols('CODE');

    for my $test (@tests) {
        subtest $test => sub {
            try { $class->$test() }
            catch ($e) { diag $e }
        };
    }
    done_testing();
    return;
}

sub _test_can ($class) {
    state @subs = qw(run call_method methods test);
    can_ok $class, \@subs, "can do: @subs";
    return;
}

sub _test_methods ($class) {
    my $mock = mock 'WebService::FOAAS' => ( track => 1 );

    for my $method ( $class->methods() ) {
        $mock->override( $method => 1 );

        ok lives { $class->call_method($method) },
          "$method lives";
        ok scalar $mock->sub_tracking->{$method}->@*,
          "$method called";
    }
    return;
}

sub _test_service_failure ($class) {
    my $mock = mock 'WebService::FOAAS';

    for my $method ( $class->methods() ) {
        $mock->override( $method => sub { die 'mocked' } );

        my $exception =
          dies { $class->call_method($method) };
        isa_ok $exception, [ServiceError],
          "$method throws ServiceError on failure";
        like $exception->message, qr/^mocked/,
          "correct error in $method exception";
    }
    return;
}

1;

[Updated, thanks to Dan Book, Karen Etheridge, and Bob Kleemann] The only goofy bit above is the need to put the exception calls in a BEGIN block and then explic­it­ly call BEGIN { Local::CallFOAAS::Exceptions->import() }. Since the two pack­ages are in the same file, I can’t do a use state­ment since the implied require would look for a cor­re­spond­ing file or entry in %INC. (You can get around this by mess­ing with %INC direct­ly or through a mod­ule like me::inlined that does that mess­ing for you, but for a single-​purpose mod­uli­no like this it’s fine.)


happy man funny sticking tongue out

Over the past two years, I’ve got­ten back into play­ing Dungeons & Dragons, the famous table­top fan­ta­sy role-​playing game. As a soft­ware devel­op­er and musi­cian, one of my favorite char­ac­ter class­es to play is the bard, a mag­i­cal and inspir­ing per­former or word­smith. The list of basic bardic spells includes Vicious Mockery, enchant­i­ng ver­bal barbs that have the pow­er to psy­chi­cal­ly dam­age and dis­ad­van­tage an oppo­nent even if they don’t under­stand the words. (Can you see why this is so appeal­ing to a coder?)

Mocking has a role to play in soft­ware test­ing as well, in the form of mock objects that sim­u­late parts of a sys­tem that are too brit­tle, too slow, too com­pli­cat­ed, or oth­er­wise too finicky to use in real­i­ty. They enable dis­crete unit test­ing with­out rely­ing on depen­den­cies exter­nal to the code being test­ed. Mocks are great for data­bas­es, web ser­vices, or oth­er net­work resources where the goal is to test what you wrote, not what’s out in the cloud” somewhere.

Speaking of web ser­vices and mock­ing, one of my favorites is the long-​running FOAAS (link has lan­guage not safe for work), a sur­pris­ing­ly expan­sive RESTful insult ser­vice. There’s a cor­re­spond­ing Perl client API, of course, but what I was miss­ing was a handy Perl script to call that API from the ter­mi­nal com­mand line. So I wrote the fol­low­ing over Thanksgiving break, try­ing to keep it sim­ple while also show­ing the basics of mock­ing such an API. It also demon­strates some new­er Perl syn­tax and test­ing tech­niques as well as bri­an d foys mod­uli­no con­cept from Mastering Perl (sec­ond edi­tion, 2014) that mar­ries script and mod­ule into a self-​contained exe­cutable library.

#!/usr/bin/env perl

package Local::CallFOAAS;  # this is a modulino
use Test2::V0;             # enables strict, warnings, utf8

# declare all the new stuff we're using
use feature qw(say state);
use experimental qw(isa postderef signatures);
use Feature::Compat::Try;
use Syntax::Construct qw(non-destructive-substitution);

use WebService::FOAAS ();
use Package::Stash;
use Exception::Class (
    NoMethodException => {
        alias  => 'throw_no_method',
        fields => 'method',
    },
    ServiceException => { alias => 'throw_service' },
);

my $foaas = Package::Stash->new('WebService::FOAAS');

my $run_as =
    !!$ENV{CPANTEST}       ? 'test'
  : !defined scalar caller ? 'run'
  :                          undef;
__PACKAGE__->$run_as(@ARGV) if defined $run_as;

sub run ( $class, @args ) {
    try { say $class->call_method(@args) }
    catch ($e) {
        die 'No method ', $e->method, "\n"
          if $e isa NoMethodException;
        die 'Service error: ', $e->error, "\n"
          if $e isa ServiceException;
        die "$e\n";
    }
    return;
}

# Utilities

sub methods ($) {
    state @methods = sort map s/^foaas_(.+)/$1/r,
      grep /^foaas_/, $foaas->list_all_symbols('CODE');
    return @methods;
}

sub call_method ( $class, $method = '', @args ) {
    state %methods = map { $_ => 1 } $class->methods();
    throw_no_method( method => $method )
      unless $methods{$method};
    return do {
        try { $foaas->get_symbol("&$method")->(@args) }
        catch ($e) { throw_service( error => $e ) }
    };
}

# Testing

sub test ( $class, @ ) {
    state $stash = Package::Stash->new($class);
    state @tests = sort grep /^_test_/,
      $stash->list_all_symbols('CODE');

    for my $test (@tests) {
        subtest $test => sub {
            try { $class->$test() }
            catch ($e) { diag $e }
        };
    }
    done_testing();
    return;
}

sub _test_can ($class) {
    state @subs = qw(run call_method methods test);
    can_ok( $class, \@subs, "can do: @subs" );
    return;
}

sub _test_methods ($class) {
    my $mock = mock 'WebService::FOAAS' => ( track => 1 );

    for my $method ( $class->methods() ) {
        $mock->override( $method => 1 );

        ok lives { $class->call_method($method) },
          "$method lives";
        ok scalar $mock->sub_tracking->{$method}->@*,
          "$method called";
    }
    return;
}

sub _test_service_failure ($class) {
    my $mock = mock 'WebService::FOAAS';

    for my $method ( $class->methods() ) {
        $mock->override( $method => sub { die 'mocked' } );

        my $exception =
          dies { $class->call_method($method) };
        isa_ok $exception, ['ServiceException'],
          "$method throws ServiceException on failure";
        like $exception->error, qr/^mocked/,
          "correct error in $method exception";
    }
    return;
}

1;

Let’s walk through the code above.

Preliminaries

First, there’s a gener­ic she­bang line to indi­cate that Unix and Linux sys­tems should use the perl exe­cutable found in the user’s PATH via the env com­mand. I declare a pack­age name (in the Local:: name­space) so as not to pol­lute the default main pack­age of oth­er scripts that might want to require this as a mod­ule. Then I use the Test2::V0 bun­dle from Test2::Suite since the embed­ded test­ing code uses many of its func­tions. This also has the side effect of enabling the strict, warn­ings, and utf8 prag­mas, so there’s no need to explic­it­ly use them here.

(Why Test2 instead of Test::More and its deriv­a­tives and add-​ons? Both are main­tained by the same author, who rec­om­mends the for­mer. I’m see­ing more and more mod­ules using it, so I thought this would be a great oppor­tu­ni­ty to learn.)

I then declare all the new-​ish Perl fea­tures I’d like to use that need to be explic­it­ly enabled so as not to sac­ri­fice back­ward com­pat­i­bil­i­ty with old­er ver­sions of Perl 5. As of this writ­ing, some of these fea­tures (the isa class instance oper­a­tor, named argu­ment sub­rou­tine sig­na­tures, and try/​catch excep­tion han­dling syn­tax) are con­sid­ered experimental, with the lat­ter enabled in old­er ver­sions of Perl via the Feature::Compat::Try mod­ule. The friend­lier post­fix deref­er­enc­ing syn­tax was main­lined in Perl ver­sion 5.24, but ver­sions 5.20 and 5.22 still need it exper­i­men­tal. Finally, I use Syntax::Construct to announce the /r flag for non-​destructive reg­u­lar expres­sion text sub­sti­tu­tions intro­duced in ver­sion 5.14.

Next, I bring in the afore­men­tioned FOAAS Perl API with­out import­ing any of its func­tions, Package::Stash to make metapro­gram­ming eas­i­er, and a cou­ple of excep­tion class­es so that the com­mand line func­tion and oth­er con­sumers might bet­ter tell what caused a fail­ure. In prepa­ra­tion for the meth­ods below dynam­i­cal­ly dis­cov­er­ing what func­tions are pro­vid­ed by WebService::FOAAS, I gath­er up its sym­bol table (or stash) into the $foaas variable.

The next block deter­mines how, if at all, I’m going to run the code as a script. If the CPANTEST envi­ron­ment vari­able is set, I’ll call the test class method sub, but if there’s no sub­rou­tine call­ing me I’ll exe­cute the run class method. Either will receive the com­mand line argu­ments from @ARGV. If nei­ther of these con­di­tions is true, do noth­ing; the rest of the code is method declarations.

Modulino methods, metaprogramming, and exceptions

The first of these is the run method. It’s a thin wrap­per around the call_method class method detailed below, either out­putting its result or dieing with an appro­pri­ate error depend­ing on the class of excep­tion thrown. Although I chose not to write tests for this out­put, future tests might call this method and catch these rethrown excep­tions to match against them. The mes­sages end with a \n new­line char­ac­ter so die knows not to append the cur­rent script line number.

Next is a util­i­ty method called methods that uses Package::Stash’s list_all_symbols to retrieve the names of all named CODE blocks (i.e., subs) from WebService::FOAAS’s sym­bol table. Reading from right to left, these are then fil­tered with grep to only find those begin­ning in foaas_ and then trans­formed with map to remove that pre­fix. The list is then sorted and stored in a state vari­able and returned so it need not be ini­tial­ized again.

(As an aside, although perlcritic stern­ly warns against it I’ve cho­sen the expres­sion forms of grep and map here over their block forms for sim­plic­i­ty’s sake. It’s OK to bend the rules if you have a good reason.)

sub call_method is where the real action takes place. Its para­me­ters are the class that called it, the name of a FOAAS $method (default­ed to the emp­ty string), and an array of option­al argu­ments in @args. I build a hash or asso­cia­tive array from the ear­li­er methods method which I then use to see if the passed method name is one I know about. If not, I throw a NoMethodException using the throw_no_method alias func­tion cre­at­ed when I used Exception::Class at the begin­ning. Using a func­tion instead of NoMethodException->throw() means that it’s checked at com­pile time rather than run­time, catch­ing typos.

I get the sub­rou­tine (denot­ed by a & sig­il) named by $method from the $foaas stash and pass it any fur­ther received argu­ments from @args. If that WebService::FOAAS sub­rou­tine throws an excep­tion it’ll be caught and re-​thrown as a ServiceException; oth­er­wise call_method returns the result. It’s up to the caller to deter­mine what, if any­thing, to do with that result or any thrown exceptions.

Testing the modulino with mocks

This is where I start using those Test2::Suite tools I men­tioned at the begin­ning. The test class method starts by build­ing a fil­tered list of all subs begin­ning with _test_ in the cur­rent class, much like methods did above with WebService::FOAAS. I then loop through that list of subs, run­ning each as a subtest con­tain­ing a class method with any excep­tions report­ed as diag­nos­tics.

The rest of the mod­uli­no is sub­test meth­ods, start­ing with a sim­ple _test_can san­i­ty check for the pub­lic meth­ods in the class. Following that is _test_methods, which starts by mocking the WebService::FOAAS pack­age and telling Test2::Mock I want to track any added, over­rid­den, or set subs. I then loop through all the method names returned by the methods class method, overrideing each one to return a sim­ple true val­ue. I then test pass­ing those names to call_method and use the hash ref­er­ence returned by sub_tracking to check that the over­rid­den sub was called. This seems a lot sim­pler than the Test::Builder-based mock­ing libraries I’ve tried like Test::MockModule and Test::MockObject.

_test_service_failure acts in much the same way, check­ing that call_method cor­rect­ly throws ServiceExceptions if the wrapped WebService::FOAAS func­tion dies. The main dif­fer­ence is that the mocked WebService::FOAAS subs are now over­rid­den with a code ref­er­ence (sub { die 'mocked' }), which call_method uses to pop­u­late the rethrown ServiceExceptions error field.

Wrapping up

With luck, this arti­cle has giv­en you some ideas, whether it’s in mak­ing scripts (per­haps lega­cy code) testable to improve them, or writ­ing bet­ter unit tests that mock depen­den­cies, or delv­ing a lit­tle into metapro­gram­ming so you can dynam­i­cal­ly sup­port and test new fea­tures of said depen­den­cies. I hope you haven’t come away too offend­ed, at least. Let me know in the com­ments what you think.

woman using a laptop with her daughter

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…

base and parent

In 1997 Perl 5.004_04 intro­duced the base prag­ma (back when Perl used that kind of ver­sion­ing scheme; in these days of seman­tic ver­sion­ing we’d call it ver­sion 5.4.4). It does the above BEGIN block in a sin­gle line:

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

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

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

use parent 'Local::MyParentClass';

A cou­ple of years ago my Newfold Digital col­league David Oswald cre­at­ed a fork of par­ent called parent::versioned that 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­tems on CPAN that pro­vide syn­tac­tic sug­ar and extra fea­tures to Perl’s min­i­mal but flex­i­ble basics. Two of the more pop­u­lar ones, Moose and Moo, offer an extends key­word that you should use instead of use parent so 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::NonMoose mod­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::Pad mod­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 week about con­sid­er­ing a more self-​consistent syntax.

Multiple inheritance vs. 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::Role uses 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 role key­word, and both class­es and roles use does to 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 caveat about 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 SUPER pseudo-​class to Moose’s override and super key­words, to Moose’s and Moo’s method 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­ing and mod­i­fy­ing meth­ods before, and when it comes to Moose and Moo code I’m now on the side of using the around method mod­i­fi­er if 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 SUPER in their methods with an :override attribute 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­tem will 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?

animal antler big close up

At my work, we exten­sive­ly use the Moose object sys­tem to take care of what would ordi­nar­i­ly be very tedious boil­er­plate object-​oriented Perl code. In one part of the code­base, we have a fam­i­ly of class­es that, among oth­er things, map Perl meth­ods to the names of var­i­ous calls in a third-​party API with­in our larg­er orga­ni­za­tion. Those pri­vate Perl meth­ods are in turn called from pub­lic meth­ods pro­vid­ed by roles con­sumed by these class­es so that oth­er areas aren’t con­cerned with said API’s details.

Without going into too many specifics, I had a bunch of class­es all with sec­tions that looked like this:

sub _create_method    { return 'api_add'     }
sub _retrieve_method  { return 'api_info'    }
sub _search_method    { return 'api_list'    }
sub _update_method    { return 'api_update'  }
sub _cancel_method    { return 'api_remove'  }
sub _suspend_method   { return 'api_disable' }
sub _unsuspend_method { return 'api_restore' }

... # etc.

The val­ues returned by these very sim­ple meth­ods might dif­fer from class to class depend­ing on the API call need­ed, and dif­fer­ent class­es might have a dif­fer­ent mix of these meth­ods depend­ing on what roles they consume.

These meth­ods had built up over time as devel­op­ers had expand­ed the class­es’ func­tion­al­i­ty, and this week it was my turn. I decid­ed to apply the DRY (don’t repeat your­self) prin­ci­ple and cre­ate them from a sim­ple hash table like so:

my %METHOD_MAP = (
  _create_method    => 'api_add',
  _retrieve_method  => 'api_info',
  _search_method    => 'api_list',
  _update_method    => 'api_update',
  _cancel_method    => 'api_remove',
  _suspend_method   => 'api_disable',
  _unsuspend_method => 'api_restore',
);

At first, I thought to myself, These look like pri­vate read-​only attrib­ut­es!” So I wrote:

use Moose;

...

has $_ => (
  is       => 'ro',
  init_arg => undef,
  default  => $METHOD_MAP{$_},
) for keys %METHOD_MAP;

Of course, I’d have to move the class­es’ with state­ments after these def­i­n­i­tions so the roles they con­sume could see” these runtime-​defined attrib­ut­es. But some of the meth­ods used to read these are class meth­ods (e.g., called as ClassName->foo() rather than $object->foo()), and Moose attrib­ut­es are only set after the con­struc­tion of a class instance.

Then I thought, Hey, Moose has a MOP (meta-​object pro­to­col)! I’ll use that to gen­er­ate these meth­ods at runtime!”

my $meta = __PACKAGE__->meta;

while (my ($method, $api_call) = each %METHOD_MAP) {
    $meta->add_method( $method => sub {$api_call} );
}

The add_method doc­u­men­ta­tion strong­ly encourage[s]” you to pass a metamethod object rather than a code ref­er­ence, though, so that would look like:

use Moose::Meta::Method;

my $meta = __PACKAGE__->meta;

while (my ($method, $api_call) = each %METHOD_MAP) {
    $meta->add_method( $method = Moose::Meta::Method->wrap(
      sub {$api_call}, __PACKAGE__, $meta,
    );
}

This was get­ting ugly. There had to be a bet­ter way, and for­tu­nate­ly there was in the form of Dave Rolskys MooseX::ClassAttribute mod­ule. It sim­pli­fies the above to:

use MooseX::ClassAttribute;

class_has $_ => (
  is      => 'ro',
  default => $METHOD_MAP{$_},
) for keys %METHOD_MAP;

Note there’s no need for init_arg => undef to pre­vent set­ting the attribute in the con­struc­tor. Although they’re still Moose attrib­ut­es, they act like class meth­ods so long as the class con­sumes the roles that require them after the attribute definitions.

Lastly, if we were using Moo as a light­weight alter­na­tive to Moose, I could have instead select­ed Toby Inksters MooX::ClassAttribute. Although it has some caveats, it’s pret­ty much the only alter­na­tive to our ini­tial class method def­i­n­i­tions as Moo lacks a meta-​object pro­to­col.

The les­son as always is to check CPAN (or the appro­pri­ate mix of your language’s soft­ware repos­i­to­ry, forums like Stack Overflow, etc.) for any­thing that could con­ceiv­ably have appli­ca­tion out­side of your par­tic­u­lar cir­cum­stances. Twenty-​five years into my career and I’m still leap­ing into code with­out first con­sid­er­ing that some­one smarter than me has already done the work.

Look, I get it. You don’t like the Perl pro­gram­ming lan­guage or have oth­er­wise dis­re­gard­ed it as dead.” (Or per­haps you haven’t, in which case please check out my oth­er blog posts!) It has weird noisy syn­tax, mix­ing reg­u­lar expres­sions, sig­ils on vari­able names, var­i­ous braces and brack­ets for data struc­tures, and a menagerie of cryp­tic spe­cial vari­ables. It’s old: 34 years in December, with a his­to­ry of (some­times ama­teur) devel­op­ers that have used and abused that syn­tax to ship code of ques­tion­able qual­i­ty. Maybe you grudg­ing­ly accept its util­i­ty but think it should die grace­ful­ly, main­tained only to run lega­cy applications.

But you know what? Perl’s still going. It’s had a steady cadence of year­ly releas­es for the past decade, intro­duc­ing new fea­tures and fenc­ing in bad behav­ior while main­tain­ing an admirable lev­el of back­ward com­pat­i­bil­i­ty. Yes, there was a too-​long adven­ture devel­op­ing what start­ed as Perl 6, but that lan­guage now has its own iden­ti­ty as Raku and even has facil­i­ties for mix­ing Perl with its native code or vice versa.

And then there’s CPAN, the Comprehensive Perl Archive Network: a continually-​updated col­lec­tion of over 200,000 open-​source mod­ules writ­ten by over 14,000 authors, the best of which are well-​tested and ‑doc­u­ment­ed (apply­ing peer pres­sure to those that fall short), pre­sent­ed through a search engine and front-​end built by scores of con­trib­u­tors. Through CPAN you can find dis­tri­b­u­tions for things like:

All of this is avail­able through a mature instal­la­tion tool­chain that doesn’t break from month to month.

Finally and most impor­tant­ly, there’s the glob­al Perl com­mu­ni­ty. The COVID-​19 pan­dem­ic has put a damper on the hun­dreds of glob­al Perl Mongers groups’ mee­tups, but that hasn’t stopped the year­ly Perl and Raku Conference from meet­ing vir­tu­al­ly. (In the past there have also been year­ly European and Asian con­fer­ences, occa­sion­al for­ays into South America and Russia, as well as hackathons and work­shops world­wide.) There are IRC servers and chan­nels for chat, mail­ing lists galore, blogs (yes, apart from this one), and a quirky social net­work that pre­dates Facebook and Twitter.

So no, Perl isn’t dead or even dying, but if you don’t like it and favor some­thing new­er, that’s OK! Technologies can coex­ist on their own mer­its and advo­cates of one don’t have to beat down their con­tem­po­raries to be suc­cess­ful. Perl hap­pens to be battle-​tested (to bor­row a term from my friend Curtis Ovid” Poe), it runs large parts of the Web (speak­ing from direct and ongo­ing expe­ri­ence in the host­ing busi­ness here), and it’s still evolv­ing to meet the needs of its users.

woman in black tank top and blue denim jeans

This blog has devot­ed a fair amount of atten­tion to the pop­u­lar and mul­ti­fac­eted object-​oriented sys­tem Moose and its light­weight sub­set Moo. I’ve also cov­ered Object::Pad, the test­bed of con­cepts and syn­tax for Corinna, the pro­posed next-​generation Perl core OO sys­tem. But what if your project is too memory‑, performance‑, or dependency-​constrained for these options?

It turns out that CPAN has a rich his­to­ry of lighter-​weight OO mod­ules to meet many dif­fer­ent needs. If you can live with their trade-​offs, they’re worth inves­ti­gat­ing instead of rolling your own lay­er over Perl’s OO. Here are a few.

Class::Struct

Class::Structs main claim to fame is its inclu­sion in the stan­dard Perl dis­tri­b­u­tion, so there’s no need to install depen­den­cies from CPAN. It pro­vides a syn­tax for defin­ing class­es as C‑style structs at either com­pile time or run­time. (There’s no speed advan­tage to the for­mer; it just means that your class will be built as if you had writ­ten the acces­sors your­self as subs.) Here’s an example:

#!/usr/bin/env perl

use v5.24; # for strict, say, and postfix dereferencing
use warnings;

package Local::MyClass;
use Class::Struct (
    foo => '$',
    bar => '@',
    baz => '%',
);

package main;

my $obj = Local::MyClass->new(
    foo => 'hello',
    bar => [1, 2, 3],
    baz => { name => 'Mark'},
);

say $obj->foo, ' ', $obj->baz('name');
say join ',', $obj->bar->@*;

# replace the name element of baz
$obj->baz(name => 'Sharon');

# replace the second element of bar
$obj->bar(1, 'replaced');
say $obj->foo, ' ', $obj->baz('name');
say join ',', $obj->bar->@*;

And here’s the output:

hello Mark
1,2,3
hello Sharon
1,replaced,3

Note that Class::Struct sup­ports acces­sors for scalar, array, and hash types, as well as oth­er class­es (not demon­strat­ed). Consult the module’s doc­u­men­ta­tion for the dif­fer­ent ways to define and retrieve them.

Class::Accessor

Class::Accessor does one thing: it makes acces­sors and muta­tors (also known as get­ters and set­ters) for fields in your class. Okay, it actu­al­ly does anoth­er thing: it pro­vides your class with a new method to ini­tial­ize those fields. Those acces­sors can be read-​write, read-​only, or write-​only. (Why would you want write-​only acces­sors?) You can define any of them using either its his­tor­i­cal class meth­ods or a Moose-​like attribute syn­tax.

If you’re try­ing to squeeze every bit of per­for­mance out of your code and can sac­ri­fice a lit­tle flex­i­bil­i­ty in alter­ing acces­sor behav­ior, you can opt for Class::Accessor::Fast or Class::Accessor::Faster. The for­mer still uses hash ref­er­ences under the hood to rep­re­sent objects and the lat­ter uses array ref­er­ences. The main Class::Accessor doc­u­men­ta­tion con­tains an effi­cien­cy com­par­i­son of the three for your edification.

Here’s an exam­ple script using Class::Accessor::Faster and the Moose-​like syntax:

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::MyClass;
use Class::Accessor::Faster 'moose-like';

has readwrite => (is => 'rw');
has readonly  => (is => 'ro');

package main;

my $obj = Local::MyClass->new( { # must be a hash reference
    readwrite => 'hello',
    readonly  => 'world',
} );

say $obj->readwrite, ' ', $obj->readonly;
$obj->readwrite('greetings');
say $obj->readwrite, ' ', $obj->readonly;

# throws an error
$obj->readonly('Cleveland');

And here is its output:

hello world
greetings world
'main' cannot alter the value of 'readonly' on objects of class 'Local::MyClass' at ./caf.pl line 24.

Class::Tiny

Class::Tiny both does less and more than Class::Accessor. All of its gen­er­at­ed acces­sors are read-​write, but you can also give their attrib­ut­es lazy defaults. Its gen­er­at­ed con­struc­tor takes argu­ments via either a Class::Accessor-style hash ref­er­ence or a plain list of key/​value pairs, so that’s a lit­tle more con­ve­nient. It also sup­ports Moose-​style BUILDARGS, BUILD, and DEMOLISH meth­ods for argu­ment adjust­ment, val­i­da­tion, and object cleanup, respectively.

It’s a toss-​up as to which of the pre­vi­ous two is bet­ter.” You’ll have to exam­ine their respec­tive fea­tures and deter­mine which ones map to your needs.

Here’s an exam­ple script that shows a few of Class::Tiny’s unique features:

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::MyClass;
use Class::Tiny qw<foo bar>,
{
    baz       => 'default baz',
    timestamp => sub { time },
};

package main;

my $obj = Local::MyClass->new( # plain key-values OK
    foo => 'hello',
    bar => 'world',
);

say $obj->foo, ' ', $obj->bar;
say 'Object built on ', scalar localtime $obj->timestamp;
$obj->foo('greetings');
$obj->bar('Cleveland');
say $obj->foo, ' ', $obj->bar;
say $obj->baz;

And its output:

hello world
Object built on Tue Sep  7 09:00:00 2021
greetings Cleveland
default baz

Object::Tiny

For an even more min­i­mal­ist approach, con­sid­er Object::Tiny. Its acces­sors are read-​only, it gives you a sim­ple con­struc­tor, and that’s it. Its doc­u­men­ta­tion lists a num­ber of rea­sons why it can be supe­ri­or to Class::Accessor, includ­ing low­er mem­o­ry usage and less typ­ing. There’s also a fork called Object::Tiny::RW that adds read-​write sup­port to its accessors.

Class::Tiny’s doc­u­men­ta­tion con­tains a fea­ture table com­par­i­son of it, Object::Tiny, and Class::Accessor. This may help you decide which to use.

Here’s an exam­ple script:

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::MyClass;
use Object::Tiny qw<foo bar>;

package main;

my $obj = Local::MyClass->new(
    foo => 'hello',
    bar => 'world',
);

say $obj->foo, ' ', $obj->bar;

# has no effect unless you use Object::Tiny::RW
$obj->foo('greetings');
say $obj->foo, ' ', $obj->bar;

And its output:

hello world
hello world

Add some speed with XS

If the above options are still too slow and you don’t mind requir­ing a C com­pil­er to install them, there are vari­ants that use Perl’s XS inter­face instead of pure Perl code:

Roles with Role::Tiny

If you’re eye­ing Moose and Moo’s sup­port for roles (also known as traits) as an alter­na­tive to inher­i­tance but still want to keep things light with one of the above mod­ules, you’re in luck. The Role::Tiny mod­ule lets you com­pose meth­ods into con­sum­ing class­es with Moo-​like syn­tax and will pull in Common Lisp Object System-style method mod­i­fi­er sup­port from Class::Method::Modifiers if you need it. It does mean anoth­er cou­ple of CPAN depen­den­cies, so if that’s a prob­lem in your sit­u­a­tion you’ll just have to live with­out roles.

Here’s an exam­ple script with a role and a con­sum­ing class that uses Class::Tiny. The role requires that its con­sumers imple­ment a required_method, pro­vides a foo method that uses it, and a method mod­i­fi­er for bar.

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::MyRole;
use Role::Tiny;

requires 'required_method';

sub foo {
    my $self = shift;
    say $self->required_method();
}

before bar => sub {
    warn 'About to call bar...';
};

package Local::MyClass;
use Class::Tiny {name => ''};
use Role::Tiny::With;
with 'Local::MyRole';

sub bar {
    my ($self, $greeting) = @_;
    say "$greeting ", $self->name;
}

sub required_method {
    my $self = shift;
    return 'Required by Local::MyRole';
}

package main;

my $obj = Local::MyClass->new(name => 'Mark');
$obj->bar('hello');

$obj->name('Sharon');
$obj->bar('salutations');

$obj->foo();

And its output:

About to call bar... at ./rt.pl line 17.
hello Mark
About to call bar... at ./rt.pl line 17.
salutations Sharon
Required by Local::MyRole

What’s your favorite?

There will always be those who insist on writ­ing every­thing long­hand, but mod­ules like these can save a lot of time and typ­ing as well as reduce errors. Do you have a favorite, maybe some­thing I missed? Let me know in the comments.

black deer lying on plants near green trees during daytime

Last month I wrote about using Moose’s override func­tion to, well, over­ride a superclass’s method. Chris Prather on the #moose IRC chan­nel sug­gest­ed soon after that the around method mod­i­fi­er (or its lit­tle sis­ters before and after) might be a bet­ter choice if you’re also call­ing the orig­i­nal method inside. He not­ed that at a min­i­mum override only works if you’re sub­class­ing, around will apply to com­posed meth­ods too.”

His point was that when you decide to com­pose roles (also know as traits) instead of or in addi­tion to more tra­di­tion­al inher­i­tance, override sim­ply doesn’t work: only a method mod­i­fi­er will do. (And as Graham Knop and Karen Etheridge lat­er remarked on IRC, override isn’t even an option if you’re using Moo as an alter­na­tive to Moose.)

Modifying a role’s method with around might look like this:

#!/usr/bin/env perl

use v5.12; # for strict and say
use warnings;

package Local::Role::Hungry;
use Moose::Role;
requires 'name';

sub wants_food {
my $self = shift;
say $self->name, ' is hungry!';
return;
}

package Local::GuineaPig;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
my ($orig, $self, @args) = @_;
say $self->name, ' runs to the front of the cage!';
$self->$orig(@args);
say 'Wheek!';
return;
};

package Local::Dog;
use Moose;
has name => (is => 'ro');
with 'Local::Role::Hungry';

around wants_food => sub {
my ($orig, $self, @args) = @_;
say $self->name, ' runs to the kitchen!';
$self->$orig(@args);
say 'Woof!';
return;
};

before wants_food => sub {
my $self = shift;
say $self->name, ' is jumping!';
};

package main;
my $dog = Local::Dog->new(name => 'Seamus');
my @pigs = map { Local::GuineaPig->new(name => $_) }
qw<Cocoa Ginger Pepper>;

for my $animal ($dog, @pigs) {
$animal->wants_food();
}

Running the above yields:

Seamus runs to the kitchen!
Seamus is hungry!
Woof!
Cocoa runs to the front of the cage!
Cocoa is hungry!
Wheek!
Ginger runs to the front of the cage!
Ginger is hungry!
Wheek!
Pepper runs to the front of the cage!
Pepper is hungry!
Wheek!

It’s a lit­tle more involved than over­rid­ing a sub, since method mod­i­fiers are passed both the con­sumed role’s orig­i­nal method ($orig above) and the instance ($self above) as para­me­ters. It has the same effect, though, and you can call the orig­i­nal method by say­ing $self->$orig(parameters).

If all you want to do is have some­thing hap­pen either before or after the orig­i­nal method, just use before or after:

before wants_food => sub {
my $self = shift;
say $self->name, ' is jumping!';
};

Note that there’s no return val­ue in a before or after mod­i­fi­er, as those are han­dled by the orig­i­nal method.

Modifiers aren’t lim­it­ed to con­sum­ing class­es; they can be in roles and mod­i­fy their con­sumers’ meth­ods. They also have a cou­ple of oth­er tricks:

  • You can pass an array ref­er­ence to mod­i­fy mul­ti­ple meth­ods at once.
  • You can use the con­tents of a vari­able to spec­i­fy the mod­i­fied method name, and use that same vari­able in the mod­i­fi­er itself.
  • You can use a reg­u­lar expres­sion to select meth­ods. (Beware if you’re using Moo that its Class::Method::Modifiers mod­ule doesn’t sup­port this.)

Putting these togeth­er gives you con­structs like these:

after qw<foo bar baz> => sub {
say 'Something got called';
};

for my $method_name (qw<foo bar baz>) {
before $method_name => sub {
say "Calling $method_name...";
};
}

before qr/^request_/ => sub {
my ($self, @args) = @_;
$self->is_valid(@args) or die 'Invalid arguments';
};

Moose comes with great intro­duc­to­ry man­u­als for method mod­i­fiers and roles, so be sure to check those out. There’s a lot more to them and a blog can only cov­er so much.

close up of gear shift over black background

Last week found me explor­ing Object::Pad as an alter­na­tive to the Moo object-​oriented frame­work for Perl since the for­mer is pro­to­typ­ing the syn­tax and con­cepts for a pro­posed built-​in OO frame­work named Corinna. I had to put that par­tic­u­lar project on hold as dbcrit­ics cur­rent design is a bit too role-​happy and Object::Pad cur­rent­ly lacks method mod­i­fiers as in Moo. (Corinna is explic­it­ly skip­ping them for its cur­rent min­i­mum viable prod­uct.) Thankfully, devel­op­ment con­tin­ues at a rapid pace. For instance, author Paul Evans has already addressed a prob­lem I ran into when attempt­ing to exam­ine slot val­ues in the debugger.

But I want­ed to high­light a point I made in one of the com­ments last week: Object::Pad’s slots (a.k.a. fields, attrib­ut­es, what­ev­er) are pri­vate by default, com­plete­ly unex­posed to oth­er class instances unless they mon­key with the meta-​object pro­to­col. Unless you explic­it­ly define or gen­er­ate some kind of acces­sor method, these slots act like lex­i­cal (a.k.a. my) vari­ables and are only avail­able to meth­ods with­in the class.

Here’s an example:

use v5.14; # for say and package blocks
use Object::Pad 0.50;
use Feature::Compat::Try;

class Local::MyClass {
    has $arg           :param  = 'hello';
    has $readable_slot :reader = 'world';
    has $private_slot          = 'shh';

    method show_slots {
        say "You passed me $arg in the constructor.";
        say "I can see $readable_slot and you can use it as a reader.";
        say "Here's me using the reader too: ", $self->readable_slot;
        say "But only I can see $private_slot.";
        return;
    }
}

package main {
    my $obj = Local::MyClass->new(arg => 'foo');
    $obj->show_slots();
    say $obj->readable_slot;

    # Nope: Not a HASH reference
    try { say $obj->{private_slot} } catch ($e) { say "Nope: $e" }

    # Nope: Can't locate object method "private_slot" via package "Local::MyClass"
    try { say $obj->private_slot } catch ($e) { say "Nope: $e" }
}

This stands in stark con­trast to Perl’s more low-​tech hashref-​based objects, where all attrib­ut­es are avail­able sim­ply through deref­er­enc­ing the instance, e.g., $object->{foo}. Although dis­cour­aged, OO purists some­times ding Perl for this kind of unen­forced encap­su­la­tion, and I myself have seen code­bas­es that vio­late it despite the con­ven­tion of pre­ced­ing pri­vate method and attribute names with an under­score (_).

Unfortunately, there is not yet any way to declare an Object::Pad method pri­vate. You could use lex­i­cal sub­rou­tines, but then you lose the con­ve­nience of a pre-​made $self vari­able and acces­si­bil­i­ty through the MOP. The Corinna pro­pos­al lists sev­er­al dif­fer­ent types of meth­ods includ­ing pri­vate ones, so maybe this is an area for future Object::Pad development.

Another open ques­tion from the com­ments: How is [Object::Pad] on mem­o­ry and speed com­pared to Moo and blessed objects?” Luckily the pro­lif­ic per­lan­car has already added Object::Pad to his Bencher::Scenarios::Accessors dis­tri­b­u­tion, and from that, it appears that between it and Moo, Object::Pad is faster on start­up, neck-​and-​neck on object con­struc­tion and acces­sor gen­er­a­tion, and slow­er on reads and writes. (Note that Object::Pad is a fast-​moving tar­get so these fig­ures may not track with the lat­est ver­sion’s changes.) It’s no sur­prise that plain blessed objects fared bet­ter than both in most sce­nar­ios except for reads, where Moo was faster than hash-​based objects but slow­er than array-based.

I expect that should Corinna be built into Perl it would nar­row that gap with blessed objects, but in my mind, the advan­tages of using an object sys­tem out­weigh the per­for­mance hit 95% of the time. As far as bench­mark­ing mem­o­ry goes, I still need to test that on a Linux box (maybe my new VPS?) once I get more famil­iar with the Bencher framework.

Introduction: The current state of play

Perl has very min­i­mal” sup­port for object-​oriented (OO) pro­gram­ming out of the box by its own admis­sion. It’s class-​based but class­es are just pack­ages used dif­fer­ent­ly. Objects are just data struc­tures blessed into a class, meth­ods are just sub­rou­tines whose first argu­ment is an object or class name, and attributes/​properties are often just the key-​value pair of a hash stored in the object. (This last is a fea­ture shared with JavaScript, whose prototype-​based objects are just col­lec­tions of key-​value pairs with the keys addressed as prop­er­ties.) You’ve got poly­mor­phism, inher­i­tance, and it’s up to you to enforce encap­su­la­tion.

This can take a lot of work to use effec­tive­ly. To help address that, sev­er­al sys­tems have been devel­oped over the years to reduce boil­er­plate and pro­vide mod­ern (or post­mod­ern”) OO fea­tures that devel­op­ers from oth­er lan­guages expect. My favorite for a while has been Moo: it’s got the fea­tures I need 90% of the time like built-​in con­struc­tors, roles (an alter­na­tive to com­po­si­tion through inher­i­tance), attrib­ut­es, type val­i­da­tion, and method mod­i­fiers for enhanced poly­mor­phism. And if I need to dig around in the guts of class­es, attrib­ut­es, and the like I can always upgrade to Moo’s big broth­er Moose and its meta-​object pro­to­col with min­i­mal effort.

Corinna, Object::Pad, and porting dbcritic

But there’s a new kid on the block. Curtis Ovid” Poe has been spear­head­ing Corinna, an effort to bring effec­tive OO to the Perl core and leapfrog [empha­sis his] the capa­bil­i­ties of many OO lan­guages today.” No CPAN mod­ules, no chain of depen­den­cies; just sol­id OO fea­tures and syn­tax built-​in. And while Corinna is a ways off from ship­ping, Paul LeoNerd” Evans (maybe I should get a cool nick­name too?) has been imple­ment­ing some of these ideas as new Perl key­word syn­tax in his Object::Pad module.

Both Ovid and LeoNerd have been ask­ing devel­op­ers to try out Object::Pad, not just as a new toy, but to get feed­back on what works and what needs to be added. So I thought I’d try port­ing an old­er small Moo-​based project named dbcrit­ic to this new real­i­ty. In the process, I learned some of the advan­tages and dis­ad­van­tages of work­ing with Object::Pad. Hopefully, this can inform both it and Corinna’s evo­lu­tion as well as oth­er curi­ous devel­op­ers’ eval­u­a­tions. You can fol­low my cod­ing efforts in this GitHub branch.

First, the mar­quee result: the code for App::DBCritic (the class I start­ed with) is clean­er and short­er, with 33 lines shaved off so far. Mainly this is due to Object::Pad’s more con­cise attribute syn­tax (called slots” in its doc­u­men­ta­tion) and lack of explic­it sup­port for Moo’s attribute coer­cion. I only used the lat­ter for one attribute in the Moo ver­sion and I’m not sure it worked par­tic­u­lar­ly well, so it was­n’t hard to jet­ti­son. But if your code sup­ports coer­cions exten­sive­ly, you’ll have to look into Object::Pad’s BUILD or ADJUST phase blocks for now.

Before, a Moo attribute with var­i­ous options:

has schema => (
    is        => 'ro',
    coerce    => 1,
    lazy      => 1,
    default   => \&_build_schema,
    coerce    => \&_coerce_schema,
    predicate => 1,
);

After, an Object::Pad slot. No coer­cion and builder code is han­dled in a lat­er ADJUST block:

has $schema :reader :param = undef;

Speaking of ADJUST blocks, it took a lit­tle bit of insight from the #perl IRC chan­nel to real­ize that they were the appro­pri­ate place for set­ting slot defaults that are com­put­ed from oth­er slots. Previously I was using a maze of depen­den­cies mix­ing Moo lazy attrib­ut­es and builder meth­ods. Clarifying the main set of option­al con­struc­tor argu­ments into a sin­gle ADJUST block helped untan­gle things, so this might be an indi­ca­tion that lazy attrib­ut­es are an antipat­tern when try­ing to write clean code. It’s also worth not­ing that Object::Pad ADJUST blocks run on object con­struc­tion, where­as Moo lazy attrib­ut­es are only built when need­ed. This tends to mat­ter for data­base access.

The ADJUST block for the $schema slot:

ADJUST {
    my @connect_info = ( $dsn, $username, $password );
    if ($class_name and eval "require $class_name") {
        $schema = $class_name->connect(@connect_info);
    }
    elsif ( not ( blessed($schema) and $schema->isa('DBIx::Class::Schema') ) ) {
        local $SIG{__WARN__} = sub {
            if ( $_[0] !~ / has no primary key at /ms ) {
                print {*STDERR} $_[0];
            }
        };
        $schema = App::DBCritic::Loader->connect(@connect_info);
    }
    croak 'No schema defined' if not $schema;
}

Object::Pad’s slots have one great advan­tage over Moo and Moose attrib­ut­es: they direct­ly sup­port Perl array and hash data struc­tures, while the lat­ter only sup­ports scalars and ref­er­ences con­tained in scalars. This means meth­ods in your class can elim­i­nate a deref­er­enc­ing step, again lead­ing to clean­er code. I used this specif­i­cal­ly in the @violations array and %elements hash slots and was very pleased with the results.

The @violations and %elements slots and their ADJUST blocks:

has %elements;

ADJUST {
    %elements = (
        Schema       => [$schema],
        ResultSource => [ map { $schema->source($_) } $schema->sources ],
        ResultSet    => [ map { $schema->resultset($_) } $schema->sources ],
    );
}

has @violations;

ADJUST {
    @violations = map { $self->_policy_loop( $_, $elements{$_} ) }
        keys %elements;
}

method violations { wantarray ? @violations : \@violations }

Issues

I did have some devel­op­ment life­cy­cle issues with Object::Pad, but they’re main­ly a result of its future-​facing syn­tax. I had to give up using perltidy and perlcritic in my build and test phas­es, respec­tive­ly: perltidy does­n’t under­stand slot attrib­ut­es like :reader and :param and will emit an error file (but code still com­piles), and sev­er­al of the perlcritic poli­cies I use report prob­lems because its PPI pars­er does­n’t rec­og­nize the new syn­tax. I could add excep­tions in the perlcriticrc file and lit­ter my code with more ## no critic anno­ta­tions than it already had, but at this point, it was eas­i­er to just dis­able it entirely.

Another thing I had to dis­able for now was my Dist::Zilla::Plugin::Test::UnusedVars-gen­er­at­ed Test::Vars test for detect­ing unused vari­ables, as it reports mul­ti­ple fail­ures for the hid­den @(Object::Pad/slots) vari­able. It does have options for ignor­ing cer­tain vari­ables, though, so I can explore using those and pos­si­bly file a pull request to ignore that vari­able by default.

Conclusion: The future looks bright

Overall I’m sat­is­fied with Object::Pad and by exten­sion some of the syn­tax that Corinna will intro­duce. I’m going to try port­ing the rest of dbcrit­ic and see if I can work around the issues I list­ed above with­out giv­ing up the kwali­tee improve­ment tools I’m used to. I’ll post my find­ings if I feel it mer­its anoth­er blog.

What do you think? Is this the future of object-​oriented Perl? Let me know in the com­ments below.