Back To The Future DeLorean

Last week saw the release of Perl 5.34.0 (you can get it here), and with it comes a year’s worth of new fea­tures, per­for­mance enhance­ments, bug fix­es, and oth­er improve­ments. It seems like a good time to high­light some of my favorite changes over the past decade and a half, espe­cial­ly for those with more dat­ed knowl­edge of Perl. You can always click on the head­ers below for the full releas­es’ perldelta pages.

Perl 5.10 (2007)

This was a big release, com­ing as it did over five years after the pre­vi­ous major 5.8 release. Not that Perl devel­op­ers were idle — but it would­n’t be until ver­sion 5.14 that the lan­guage would adopt a steady year­ly release cadence.

Due to the build-​up time, many core enhance­ments were made but the most impor­tant was arguably the feature prag­ma, enabling the addi­tion of new syn­tax that would oth­er­wise break Perl’s back­ward com­pat­i­bil­i­ty. 5.10 also intro­duced the defined-​or oper­a­tor (//), state vari­ables that per­sist their pre­vi­ous val­ue, the say func­tion for auto­mat­i­cal­ly append­ing a new­line on out­put (so much saved typ­ing), and a large col­lec­tion of improve­ments to reg­u­lar expres­sions. In addi­tion, this release intro­duced smart match­ing (~~), though ver­sion 5.18 would even­tu­al­ly rel­e­gate it to exper­i­men­tal sta­tus.

Perl 5.12 (2010)

This release also saw many new fea­tures added, but if I had to pick one mar­quee item it would be exper­i­men­tal sup­port for plug­gable key­words, which enabled authors to extend the lan­guage itself with­out mod­i­fy­ing the core. Previously one would either use plain func­tions, hacky source fil­ters, or the dep­re­cat­ed Devel::Declare mod­ule to sim­u­late this func­tion­al­i­ty. CPAN authors would go on to cre­ate all kinds of new syn­tax, some­times pro­to­typ­ing fea­tures that would even­tu­al­ly make their way into core.

Perl 5.14 (2011)

5.14 had a big list of enhance­ments, includ­ing Unicode 6.0 sup­port and a gag­gle of reg­u­lar expres­sion fea­tures. My favorite of these was the /r switch for non-​destructive sub­sti­tu­tions.

But as the first year­ly cadence release, the changes in pol­i­cy took cen­ter stage. The Perl 5 Porters (p5p) explic­it­ly com­mit­ted to sup­port­ing the two most recent sta­ble release series, pro­vid­ing secu­ri­ty patch­es only for release series occur­ring in the past three years. They also defined an explic­it com­pat­i­bil­i­ty and dep­re­ca­tion pol­i­cy, with def­i­n­i­tions for fea­tures that may be exper­i­men­tal, dep­re­cat­ed, dis­cour­aged, and removed.

Perl 5.16 (2012)

Another year, anoth­er ver­sion bump. This time the core enhance­ments were all over the map (although no enhance­ments to the map function 😀 ).

May I high­light anoth­er doc­u­men­ta­tion change, though? The perlootut Object-​Oriented Programming in Perl Tutorial replaced the old perltoot, perltooc, perlboot, and perlbot pages, pro­vid­ing an intro­duc­tion to object-​oriented design con­cepts before strong­ly rec­om­mend­ing the use of one of the OO sys­tems from CPAN. Mentioned are Moose, its alter­na­tive Mouse, Class::Accessor, Object::Tiny, and Role::Tinys usage with the lat­ter two. Later ver­sions of perlootut would rec­om­mend Moo rather than Mouse.

Perl 5.18 (2013)

As men­tioned ear­li­er, Perl 5.18 ren­dered smart­match exper­i­men­tal, as well as lex­i­cal use of the $_ vari­able. With these came a new cat­e­go­ry of warn­ings for exper­i­men­tal fea­tures and a method for over­rid­ing such warn­ings feature-​by-​feature. Fitting in with the secu­ri­ty and safe­ty theme, hash­es were over­hauled to ran­dom­ize key/​value order, increas­ing their resis­tance to algo­rith­mic com­plex­i­ty attacks.

But it was­n’t all fenc­ing in bad behav­ior. Lexical sub­rou­tines made their first (exper­i­men­tal) appear­ance, and although I con­fess I haven’t had much call for them in my work, oth­ers have come up with some inter­est­ing uses. Four years lat­er they became non-​experimental.

Perl 5.20 (2014)

Three new syn­tax fea­tures arrived in 2014: exper­i­men­tal sub­rou­tine sig­na­tures (of which I’ve writ­ten more about here), key/​value hash slices and index/​value array slices, and exper­i­men­tal post­fix deref­er­enc­ing. This last enables clean­er left-​to-​right syn­tax when deref­er­enc­ing variables:

  • @{ $array_ref } becomes $array_ref->@*
  • %{ $hash_ref } becomes $hash_ref->%*
  • Etc.

Postfix deref­er­enc­ing became non-​experimental in Perl 5.24, and vig­or­ous dis­cus­sion con­tin­ues on sub­rou­tine sig­na­tures’ future.

Perl 5.22 (2015)

Speaking of sub­rou­tine sig­na­tures, their loca­tion moved to between the sub­rou­tine name (if any) and the attribute list (if any). Previously they appeared after attrib­ut­es. The les­son? Remain con­scious of exper­i­men­tal fea­tures in your code, and be pre­pared to make changes when upgrading.

In addi­tion to the enhance­ments, secu­ri­ty updates, per­for­mance fix­es, and dep­re­ca­tions, devel­op­ers removed the his­tor­i­cal­ly notable CGI mod­ule. First added to core in 1997 in recog­ni­tion of its crit­i­cal role in enabling web devel­op­ment, it’s been sup­plant­ed by bet­ter alter­na­tives on CPAN.

Perl 5.24 (2016)

Perl 5.20s post­fix deref­er­enc­ing was no longer exper­i­men­tal, and devel­op­ers removed both lex­i­cal $_ and autoderef­er­enc­ing on calls to push, pop, shift, unshift, splice, keys, values, and each.

Perl 5.26 (2017)

The incor­po­ra­tion of exper­i­men­tal fea­tures con­tin­ued, with lex­i­cal sub­rou­tines mov­ing into full sup­port. I like the added read­abil­i­ty enhance­ments, though: indent­ed here-​documents; the /xx reg­u­lar expres­sion mod­i­fi­er for tabs and spaces in char­ac­ter class­es; and @{^CAPTURE}, %{^CAPTURE}, and %{^CAPTURE_ALL} for reg­exp match­es with a lit­tle more self-documentation.

Perl 5.28 (2018)

Experimental sub­rou­tine sig­na­ture and attribute order­ing flipped back to its Perl 5.20 sequence of attributes-​then-​signature. Bit of a roller­coast­er ride on this one. You could do worse than using some­thing like Type::Params until this set­tles and get a wide vari­ety of type con­straints in the bargain.

Perl 5.30 (2019)

Pour one out for AWK and Fortran pro­gram­mers migrat­ing to Perl: the $[vari­able for set­ting the low­er bound of arrays could no longer be set to any­thing oth­er than zero. This had a long dep­re­ca­tion cycle start­ing in Perl 5.12.

Perl 5.32 (2020)

In 2020 Perl’s devel­op­ment moved to GitHub. And once again, I’m going to high­light read­abil­i­ty enhance­ments: the exper­i­men­tal isa oper­a­tor could be used to say:

if ( $obj isa Some::Class ) { ... }

instead of

use Scalar::Util 'blessed';
if ( blessed($obj) and $obj->isa('Some::Class') { ... }

You could also chain com­par­i­son oper­a­tors, lead­ing to the more math­e­mat­i­cal­ly con­cise if ( $x < $y <= $z ) {...} rather than if ( $x < $y and $y <= $z ) {...}.

Perl 5.34 (2021)

Finally, we come to last week’s release and its intro­duc­tion of exper­i­men­tal try/​catch excep­tion han­dling syn­tax. If you need to sup­port ear­li­er ver­sions of Perl back to 5.14, you can use Feature::Compat::Try. Earlier this year I inter­viewed the fea­ture and mod­ule’s author, Paul LeoNerd” Evans, for Perl.com. This year also marked the debut of Perl’s new gov­er­nance mod­el with the appoint­ment of a Core Team and a three-​member Steering Council.

What are some of your favorite Perl improve­ments over the years? Check out the perlhist doc­u­ment for a detailed chronol­o­gy and refresh­er with the var­i­ous perldelta pages and leave me a com­ment below.

black and gray audio mixer

Pretty soon after I start­ed writ­ing Perl in 1994, I noticed that it lacked a con­struct often found in oth­er lan­guages: the switch state­ment. Not to wor­ry, though — you can achieve the same effect with a cas­cad­ing series of if-elsif state­ments, right?

Well, no, you should­n’t do that, espe­cial­ly if the chain is real­ly long. There’s even a perl­crit­ic pol­i­cy about it, which sug­gests that you use given and when instead.

But given and when (and the smart­match oper­a­tor they imply, ~~) are still con­sid­ered exper­i­men­tal, with behav­ior sub­ject to change. So what’s a respon­si­ble devel­op­er to do?

The answer is to use the for state­ment as a top­i­cal­iz­er, which is a fan­cy way of say­ing it assigns its expres­sion to $_. You can then use things that act on $_ to your heart’s con­tent, like reg­u­lar expres­sions. Here’s an example:

for ($foo) {
    /^abc/ and do {
        ...
        last;
    };
    /^def/ and do {
        ...
        last;
    };
    # FALL THRU
    ...
}

This will cov­er a lot of cas­es (haha, see what I did there? A lot of lan­guages use a case state­ment… oh, nev­er mind.) And if all you’re doing is exact string match­ing, there’s no need to bring in reg­ex­ps. You can use a hash as a lookup table:

my %lookup = (
    foo => sub { ... },
    bar => sub { ... },
);
$lookup{$match}->();

EDIT: If every alter­na­tive is assign­ing to the same vari­able, a ternary table is anoth­er pos­si­bil­i­ty. This is a chained set of ternary con­di­tion­al (? :) oper­a­tors arranged for read­abil­i­ty. I first heard about this tech­nique from Damian Conway’s Perl Best Practices (2005).

           # Name format                 # Salutation
my $salute = $name eq ''                 ? 'Dear Customer'
           : $name =~ /(Mrs?[.]?\s+\S+)/ ? "Dear $1"
           : $name =~ /(.*),\s+Ph[.]?D/  ? "Dear Dr. $1"
           :                               "Dear $name"
           ;

Note that although this is just as inef­fi­cient as a cascaded-if/​elsif, it’s more clear that it’s a sin­gle assign­ment. It’s also more com­pact, and reads like a table with columns of match­es and alternatives.

Any of these pat­terns are prefer­able to cas­cad­ing if/​elsifs. And if you want to mon­i­tor the devel­op­ment of given, when, and ~~, check this issue on GitHub. It was last com­ment­ed on eight years ago, though, so I would­n’t hold my breath.