Friday, December 17, 2021, marked the thirty-​fourth birthday of the Perl programming language, and coincidentally this year saw the release of version 5.34. There are plenty of Perl developers out there who haven’t kept up with recent (and not-​so-​recent) improvements to the language and its ecosystem, 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 syntax without breaking backward compatibility. You can enable individual features by name (e.g., use feature qw(say fc); for the say and fc keywords), or by using a feature bundle based on the Perl version that introduced them. For example, the following:

use feature ':5.34';

…gives you the equivalent 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 mouthful. Feature bundles are good. The corresponding bundle also gets implicitly loaded if you specify a minimum required Perl version, e.g., with use v5.32;. If you use v5.12; or higher, strict mode is enabled for free. So just say:

use v5.34;

And lastly, one-​liners can use the -E switch instead of -e to enable all features for that version of Perl, so you can say the following on the command line:

perl -E 'say "Hello world!"'

Instead of:

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

Which is great when you’re trying to save some typing.

The experimental pragma

Sometimes new Perl features need to be driven a couple of releases around the block before their behavior settles. Those experiments are documented in the perlexperiment page, and usually, you need both a use feature (see above) and no warnings statement to safely enable them. Or you can simply pass a list to use experimental of the features 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 expansion of the -w command-​line switch to a system of fine-​grained controls for warning against dubious constructs” that can be turned on and off depending on the lexical scope. What started as 26 main and 20 subcategories has expanded into 31 main and 43 subcategories, including warnings for the aforementioned experimental features.

As the relevant Perl::Critic policy says, Using warnings, and paying attention to what they say, is probably the single most effective way to improve the quality of your code.” If you must violate warnings (perhaps because you’re rehabilitating some legacy code), you can isolate such violations to a small scope and individual categories. Check out the strictures module on CPAN if you’d like to go further and make a safe subset of these categories fatal during development.

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

Not every new bit of Perl syntax is enabled with a feature guard. For the rest, there’s E. Choroba’s Syntax::Construct module on CPAN. Rather than having to remember which version of Perl introduced what, Syntax::Construct lets you declare only what you use and provides a helpful error message if someone tries to run your code on an older unsupported version. Between it and the feature pragma, you can prevent 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 functions only return false on failure, requiring the developer to check every time whether a file can be opened or a system command executed. The lexical autodie pragma replaces them with versions that raise an exception with an object that can be interrogated for further details. No matter how many functions or methods deep a problem occurs, you can choose to catch it and respond appropriately. This leads us to…

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

This year’s Perl v5.34 release introduced experimental try/​catch syntax for exception handling that should look more familiar to users of other languages while handling the issues surrounding using block eval and testing of the special $@ variable. If you need to remain compatible with older versions of Perl (back to v5.14), just use the Feature::Compat::Try module from CPAN to automatically select either v5.34’s native try/​catch or a subset of the functionality provided by Syntax::Keyword::Try.

Pluggable keywords

The abovementioned Syntax::Keyword::Try was made possible by the introduction of a pluggable keyword mechanism in 2010’s Perl v5.12. So was the Future::AsyncAwait asynchronous programming library and the Object::Pad testbed for new object-​oriented Perl syntax. If you’re handy with C and Perl’s XS glue language, check out Paul LeoNerd” Evans’ XS::Parse::Keyword module to get a leg up on developing your own syntax module.

Define packages with versions and blocks

Perl v5.12 also helped reduce clutter by enabling a package namespace declaration to also include a version number, instead of requiring a separate our $VERSION = ...; v5.14 further refined packages to be specified in code blocks, so a namespace declaration can be the same as a lexical scope. Putting the two together 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 older installations 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 assigning defaults to variables.

state variables only initialize once

Speaking of variables, ever want one to keep its old value the next time a scope is entered, like in a sub? Declare it with state instead of my. Before Perl v5.10, you needed to use a closure instead.

Save some typing with say

Perl v5.10’s bumper crop of enhancements also included the say function, which handles the common use case of printing a string or list of strings with a newline. It’s less noise in your code and saves you four characters. What’s not to love?

Note unimplemented code with ...

The ... ellipsis statement (colloquially yada-​yada”) gives you an easy placeholder for yet-​to-​be-​implemented code. It parses OK but will throw an exception if executed. Hopefully, your test coverage (or at least static analysis) will catch it before your users do.

Loop and enumerate arrays with each, keys, and values

The each, keys, and values functions have always been able to operate on hashes. Perl v5.12 and above make them work on arrays, too. The latter two are mainly for consistency, but you can use each to iterate over an array’s indices and values at the same time:

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

This can be problematic in non-​trivial loops, but I’ve found it helpful in quick scripts and one-liners.

delete local hash (and array) entries

Ever needed to delete an entry from a hash (e.g, an environment variable from %ENV or a signal handler from %SIG) just inside a block? Perl v5.12 lets you do that with delete local.

Paired hash slices

Jumping forward to 2014’s Perl v5.20, the new %foo{'bar', 'baz'} syntax enables you to slice a subset of a hash with its keys and values intact. Very helpful for cherry-​picking or aggregating many hashes 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 returning 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 introduced and v5.24 de-​experimentalized a more readable postfix dereferencing syntax for navigating nested data structures. Instead of using {braces} or smooshing sigils to the left of identifiers, you can use a postfixed 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 development is slinging around and picking apart complicated data structures via JSON, so I welcome anything like this to reduce the cognitive load.

when as a statement modifier

Starting in Perl v5.12, you can use the experimental switch features when keyword as a postfix modifier. For example:

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

But I don’t recommend when, given, or givens smartmatch operations as they were retconned as experiments in 2013’s Perl v5.18 and have remained so due to their tricky behavior. I wrote about some alternatives using stable syntax back in February.

Simple class inheritance with use parent

Sometimes in older object-​oriented Perl code, you’ll see use base as a pragma to establish inheritance from another class. Older still is the direct manipulation of the package’s special @ISA array. In most cases, both should be avoided in favor of use parent, which was added to core in Perl v5.10.1.

Mind you, if you’re following the Perl object-​oriented tutorial’s advice and have selected an OO system from CPAN, use its subclassing mechanism if it has one. Moose, Moo, and Class::Accessor’s antlers” mode all provide an extends function; Object::Pad provides an :isa attribute on its class keyword.

Test for class membership with the isa operator

As an alternative to the isa() method provided to all Perl objects, Perl v5.32 introduced the experimental isa infix operator:

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

The latter can take either a bareword class name or string expression, but more importantly, it’s safer as it also returns false if the left argument is undefined or isn’t a blessed object reference. The older isa() method will throw an exception in the former case and might return true if called as a class method when $my_object is actually a string of a class name that’s the same as or inherits from isa()s argument.

Lexical subroutines

Introduced in Perl v5.18 and de-​experimentalized in 2017’s Perl v5.26, you can now precede sub declarations with my, state, or our. One use of the first two is truly private functions and methods, as described in this 2018 Dave Jacoby blog and as part of Neil Bowers’ 2014 survey of private function techniques.

Subroutine signatures

I’ve written and presented extensively about signatures and alternatives over the past year, so I won’t repeat that here. I’ll just add that the Perl 5 Porters development mailing list has been making a concerted effort over the past month to hash out the remaining issues towards rendering this feature non-​experimental. The popular Mojolicious real-​time web framework also provides a shortcut for enabling signatures and uses them extensively in examples.

Indented here-​documents with <<~

Perl has had shell-​style here-​document” syntax for embedding multi-​line strings of quoted text for a long time. Starting with Perl v5.26, you can precede the delimiting string with a ~ character and Perl will both allow the ending delimiter to be indented as well as strip indentation from the embedded text. This allows for much more readable embedded 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 teachers and textbooks would often describe multiple comparisons and inequalities as a single expression. Unfortunately, when it came time to learn programming every computer language I saw required them to be broken up with a series of and (or &&) operators. With Perl v5.32, this is no more:

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

It’s more concise, less noisy, and more like what regular math looks like.

Self-​documenting named regular expression captures

Perl’s expressive regular expression matching and text-​processing prowess are legendary, although overuse and poor use of readability enhancements often turn people away from them (and Perl in general). We often use regexps for extracting data from a matched pattern. For example:

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

Named capture groups, introduced in Perl v5.10, make both the pattern more obvious 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 regular expression modifier already enables better readability by telling the parser to ignore most whitespace, allowing you to break up complicated patterns into spaced-​out groups and multiple lines with code comments. With Perl v5.26 you can specify /xx to also ignore spaces and tabs inside [bracketed] character classes, turning this:

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

…into this:

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

Set default regexp flags with the re pragma

Beginning with Perl v5.14, writing use re '/xms'; (or any combination of regular expression modifier flags) will turn on those flags until the end of that lexical scope, saving you the trouble of remembering them every time.

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

The s/// substitution and tr/// transliteration operators typically change their input directly, often in conjunction with the =~ binding operator:

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 original untouched, such as when processing an array of strings with a map? With Perl v5.14 and above, add the /r flag, which makes the substitution 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 character encoding in general are complicated beasts. Perl has handled Unicode since v5.6 and has kept pace with fixes and support for updated standards in the intervening decades. If you need to test if two strings are equal regardless of case, use the fc function introduced in Perl v5.16.

Safer processing of file arguments with <<>>

The <> null filehandle or diamond operator” is often used in while loops to process input per line coming either from standard input (e.g., piped from another program) or from a list of files on the command line. Unfortunately, it uses a form of Perl’s open function that interprets special characters such as pipes (|) that would allow it to insecurely run external commands. Using the <<>> double diamond” operator introduced in Perl v5.22 forces open to treat all command-​line arguments as file names only. For older Perls, the perlop documentation recommends the ARGV::readonly CPAN module.

Safer loading of Perl libraries and modules from @INC

Perl v5.26 removed the ability for all programs to load modules by default from the current directory, closing a security vulnerability originally identified and fixed as CVE-20161238 in previous versions’ included scripts. If your code relied on this unsafe behavior, the v5.26 release notes include steps on how to adapt.

HTTP::Tiny simple HTTP/1.1 client included

To bootstrap access to CPAN on the web in the possible absence of external tools like curl or wget, Perl v5.14 began including the HTTP::Tiny module. You can also use it in your programs if you need a simple web client with no dependencies.

Test2: The next generation of Perl testing frameworks

Forked and refactored from the venerable Test::Builder (the basis for the Test::More library that many are familiar with), Test2 was included in the core module library beginning with Perl v5.26. I’ve experimented recently with using the Test2::Suite CPAN library instead of Test::More and it looks pretty good. I’m also intrigued by Test2::Harness’ support for threading, forking, and preloading modules to reduce test run times.

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

This last item may not be included when you install Perl, but it’s where I turn for a collection of well-​regarded CPAN modules for accomplishing a wide variety of common tasks spanning from asynchronous programming to XML. Use it as a starting point or interactively select the mix of libraries appropriate to your project.


And there you have it: a selection of 34 features, enhancements, and improvements for the first 34 years of Perl. What’s your favorite? Did I miss anything? Let me know in the comments.

woman using a laptop with her daughter

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:

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…

base and parent

In 1997 Perl 5.004_04 introduced the base pragma (back when Perl used that kind of versioning scheme; in these days of semantic versioning we’d call it version 5.4.4). It does the above BEGIN block in a single line:

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

You might see use base in older code especially if it’s also using the fields pragma. However, Perl developers discourage both as the former silences certain module loading errors while the latter is at odds with the object-​oriented programming principle of encapsulation.

So use parent instead, which Perl has included since version 5.10.1 in 2009:

use parent 'Local::MyParentClass';

A couple of years ago my Newfold Digital colleague David Oswald created a fork of parent called parent::versioned that 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 systems on CPAN that provide syntactic sugar and extra features to Perl’s minimal but flexible basics. Two of the more popular ones, Moose and Moo, offer an extends keyword that you should use instead of use parent so 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::NonMoose module 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::Pad module 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 week about considering a more self-​consistent syntax.

Multiple inheritance vs. 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::Role uses 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 role keyword, and both classes and roles use does to 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 caveat about 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 SUPER pseudo-​class to Moose’s override and super keywords, to Moose’s and Moo’s method modifiers. (You can use the latter outside of Moo since it’s provided by Class::Method::Modifiers.)

I’ve written about choosing between overriding and modifying methods before, and when it comes to Moose and Moo code I’m now on the side of using the around method modifier if 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 SUPER in their methods with an :override attribute 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 system will 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?

woman in black tank top and blue denim jeans

This blog has devoted a fair amount of attention to the popular and multifaceted object-​oriented system Moose and its lightweight subset Moo. I’ve also covered Object::Pad, the testbed of concepts and syntax for Corinna, the proposed next-​generation Perl core OO system. But what if your project is too memory‑, performance‑, or dependency-​constrained for these options?

It turns out that CPAN has a rich history of lighter-​weight OO modules to meet many different needs. If you can live with their trade-​offs, they’re worth investigating instead of rolling your own layer over Perl’s OO. Here are a few.

Class::Struct

Class::Structs main claim to fame is its inclusion in the standard Perl distribution, so there’s no need to install dependencies from CPAN. It provides a syntax for defining classes as C‑style structs at either compile time or runtime. (There’s no speed advantage to the former; it just means that your class will be built as if you had written the accessors yourself 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 supports accessors for scalar, array, and hash types, as well as other classes (not demonstrated). Consult the module’s documentation for the different ways to define and retrieve them.

Class::Accessor

Class::Accessor does one thing: it makes accessors and mutators (also known as getters and setters) for fields in your class. Okay, it actually does another thing: it provides your class with a new method to initialize those fields. Those accessors can be read-​write, read-​only, or write-​only. (Why would you want write-​only accessors?) You can define any of them using either its historical class methods or a Moose-​like attribute syntax.

If you’re trying to squeeze every bit of performance out of your code and can sacrifice a little flexibility in altering accessor behavior, you can opt for Class::Accessor::Fast or Class::Accessor::Faster. The former still uses hash references under the hood to represent objects and the latter uses array references. The main Class::Accessor documentation contains an efficiency comparison of the three for your edification.

Here’s an example 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 generated accessors are read-​write, but you can also give their attributes lazy defaults. Its generated constructor takes arguments via either a Class::Accessor-style hash reference or a plain list of key/​value pairs, so that’s a little more convenient. It also supports Moose-​style BUILDARGS, BUILD, and DEMOLISH methods for argument adjustment, validation, and object cleanup, respectively.

It’s a toss-​up as to which of the previous two is better.” You’ll have to examine their respective features and determine which ones map to your needs.

Here’s an example 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 minimalist approach, consider Object::Tiny. Its accessors are read-​only, it gives you a simple constructor, and that’s it. Its documentation lists a number of reasons why it can be superior to Class::Accessor, including lower memory usage and less typing. There’s also a fork called Object::Tiny::RW that adds read-​write support to its accessors.

Class::Tiny’s documentation contains a feature table comparison of it, Object::Tiny, and Class::Accessor. This may help you decide which to use.

Here’s an example 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 requiring a C compiler to install them, there are variants that use Perl’s XS interface instead of pure Perl code:

Roles with Role::Tiny

If you’re eyeing Moose and Moo’s support for roles (also known as traits) as an alternative to inheritance but still want to keep things light with one of the above modules, you’re in luck. The Role::Tiny module lets you compose methods into consuming classes with Moo-​like syntax and will pull in Common Lisp Object System-style method modifier support from Class::Method::Modifiers if you need it. It does mean another couple of CPAN dependencies, so if that’s a problem in your situation you’ll just have to live without roles.

Here’s an example script with a role and a consuming class that uses Class::Tiny. The role requires that its consumers implement a required_method, provides a foo method that uses it, and a method modifier 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 writing everything longhand, but modules like these can save a lot of time and typing as well as reduce errors. Do you have a favorite, maybe something I missed? Let me know in the comments.

close up of gear shift over black background

Last week found me exploring Object::Pad as an alternative to the Moo object-​oriented framework for Perl since the former is prototyping the syntax and concepts for a proposed built-​in OO framework named Corinna. I had to put that particular project on hold as dbcritics current design is a bit too role-​happy and Object::Pad currently lacks method modifiers as in Moo. (Corinna is explicitly skipping them for its current minimum viable product.) Thankfully, development continues at a rapid pace. For instance, author Paul Evans has already addressed a problem I ran into when attempting to examine slot values in the debugger.

But I wanted to highlight a point I made in one of the comments last week: Object::Pad’s slots (a.k.a. fields, attributes, whatever) are private by default, completely unexposed to other class instances unless they monkey with the meta-​object protocol. Unless you explicitly define or generate some kind of accessor method, these slots act like lexical (a.k.a. my) variables and are only available to methods within 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 contrast to Perl’s more low-​tech hashref-​based objects, where all attributes are available simply through dereferencing the instance, e.g., $object->{foo}. Although discouraged, OO purists sometimes ding Perl for this kind of unenforced encapsulation, and I myself have seen codebases that violate it despite the convention of preceding private method and attribute names with an underscore (_).

Unfortunately, there is not yet any way to declare an Object::Pad method private. You could use lexical subroutines, but then you lose the convenience of a pre-​made $self variable and accessibility through the MOP. The Corinna proposal lists several different types of methods including private ones, so maybe this is an area for future Object::Pad development.

Another open question from the comments: How is [Object::Pad] on mem­o­ry and speed com­pared to Moo and blessed objects?” Luckily the prolific perlancar has already added Object::Pad to his Bencher::Scenarios::Accessors distribution, and from that, it appears that between it and Moo, Object::Pad is faster on startup, neck-​and-​neck on object construction and accessor generation, and slower on reads and writes. (Note that Object::Pad is a fast-​moving target so these figures may not track with the latest version’s changes.) It’s no surprise that plain blessed objects fared better than both in most scenarios except for reads, where Moo was faster than hash-​based objects but slower than array-based.

I expect that should Corinna be built into Perl it would narrow that gap with blessed objects, but in my mind, the advantages of using an object system outweigh the performance hit 95% of the time. As far as benchmarking memory goes, I still need to test that on a Linux box (maybe my new VPS?) once I get more familiar with the Bencher framework.

Introduction: The current state of play

Perl has very minimal” support for object-​oriented (OO) programming out of the box by its own admission. It’s class-​based but classes are just packages used differently. Objects are just data structures blessed into a class, methods are just subroutines whose first argument 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 feature shared with JavaScript, whose prototype-​based objects are just collections of key-​value pairs with the keys addressed as properties.) You’ve got polymorphism, inheritance, and it’s up to you to enforce encapsulation.

This can take a lot of work to use effectively. To help address that, several systems have been developed over the years to reduce boilerplate and provide modern (or postmodern”) OO features that developers from other languages expect. My favorite for a while has been Moo: it’s got the features I need 90% of the time like built-​in constructors, roles (an alternative to composition through inheritance), attributes, type validation, and method modifiers for enhanced polymorphism. And if I need to dig around in the guts of classes, attributes, and the like I can always upgrade to Moo’s big brother Moose and its meta-​object protocol with minimal effort.

Corinna, Object::Pad, and porting dbcritic

But there’s a new kid on the block. Curtis Ovid” Poe has been spearheading Corinna, an effort to bring effective OO to the Perl core and leapfrog [emphasis his] the capabilities of many OO languages today.” No CPAN modules, no chain of dependencies; just solid OO features and syntax built-​in. And while Corinna is a ways off from shipping, Paul LeoNerd” Evans (maybe I should get a cool nickname too?) has been implementing some of these ideas as new Perl keyword syntax in his Object::Pad module.

Both Ovid and LeoNerd have been asking developers to try out Object::Pad, not just as a new toy, but to get feedback on what works and what needs to be added. So I thought I’d try porting an older small Moo-​based project named dbcritic to this new reality. In the process, I learned some of the advantages and disadvantages of working with Object::Pad. Hopefully, this can inform both it and Corinna’s evolution as well as other curious developers’ evaluations. You can follow my coding efforts in this GitHub branch.

First, the marquee result: the code for App::DBCritic (the class I started with) is cleaner and shorter, with 33 lines shaved off so far. Mainly this is due to Object::Pad’s more concise attribute syntax (called slots” in its documentation) and lack of explicit support for Moo’s attribute coercion. I only used the latter for one attribute in the Moo version and I’m not sure it worked particularly well, so it wasn’t hard to jettison. But if your code supports coercions extensively, you’ll have to look into Object::Pad’s BUILD or ADJUST phase blocks for now.

Before, a Moo attribute with various options:

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

After, an Object::Pad slot. No coercion and builder code is handled in a later ADJUST block:

has $schema :reader :param = undef;

Speaking of ADJUST blocks, it took a little bit of insight from the #perl IRC channel to realize that they were the appropriate place for setting slot defaults that are computed from other slots. Previously I was using a maze of dependencies mixing Moo lazy attributes and builder methods. Clarifying the main set of optional constructor arguments into a single ADJUST block helped untangle things, so this might be an indication that lazy attributes are an antipattern when trying to write clean code. It’s also worth noting that Object::Pad ADJUST blocks run on object construction, whereas Moo lazy attributes are only built when needed. This tends to matter for database 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 advantage over Moo and Moose attributes: they directly support Perl array and hash data structures, while the latter only supports scalars and references contained in scalars. This means methods in your class can eliminate a dereferencing step, again leading to cleaner code. I used this specifically 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 development lifecycle issues with Object::Pad, but they’re mainly a result of its future-​facing syntax. I had to give up using perltidy and perlcritic in my build and test phases, respectively: perltidy doesn’t understand slot attributes like :reader and :param and will emit an error file (but code still compiles), and several of the perlcritic policies I use report problems because its PPI parser doesn’t recognize the new syntax. I could add exceptions in the perlcriticrc file and litter my code with more ## no critic annotations than it already had, but at this point, it was easier to just disable it entirely.

Another thing I had to disable for now was my Dist::Zilla::Plugin::Test::UnusedVars-generated Test::Vars test for detecting unused variables, as it reports multiple failures for the hidden @(Object::Pad/slots) variable. It does have options for ignoring certain variables, though, so I can explore using those and possibly file a pull request to ignore that variable by default.

Conclusion: The future looks bright

Overall I’m satisfied with Object::Pad and by extension some of the syntax that Corinna will introduce. I’m going to try porting the rest of dbcritic and see if I can work around the issues I listed above without giving up the kwalitee improvement tools I’m used to. I’ll post my findings if I feel it merits another blog.

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