circus theme party

Last week’s arti­cle got a great response on Hacker News, and this par­tic­u­lar com­ment caught my eye:

I think this is the real point about Perl code read­abil­i­ty: it gives you enough flex­i­bil­i­ty to do things how­ev­er you like, and as a result many pro­gram­mers are faced with a mir­ror that reflects their own bad prac­tices back at them.

orev, Hacker News

This is why Damian Conway’s Perl Best Practices (2005) is one of my favorite books and perlcritic, the code ana­lyz­er is one of my favorite tools. (Though the for­mer could do with an update and the lat­ter includes poli­cies that con­tra­dict Conway.) Point perlcritic at your code, maybe add some oth­er poli­cies that agree with your house style, and grad­u­al­ly ratch­et up the sever­i­ty lev­el from gen­tle” to bru­tal.” All kinds of bad juju will come to light, from waste­ful­ly using grep to hav­ing too many sub­rou­tine argu­ments to catch­ing pri­vate vari­able use from oth­er pack­ages. perlcritic offers a use­ful base­line of con­duct and you can always cus­tomize its con­fig­u­ra­tion to your own tastes.

The oth­er con­for­mance tool in a Perl devel­op­er’s belt is perltidy, and it too has a Conway-​compatible con­fig­u­ra­tion as well as its default Perl Style Guide set­tings. I’ve found that more than any­thing else, perltidy helps set­tle argu­ments both between devel­op­ers and between their code in help­ing to avoid exces­sive merge conflicts.

But apart from extra tools, Perl the lan­guage itself can be bent and even bro­ken to suit just about any­one’s agen­da. Those used to more bondage-​and-​discipline lan­guages (hi, Java!) might feel revul­sion at the lengths to which this has some­times been tak­en, but per the quote above this is less an indict­ment of the lan­guage and more of its less method­i­cal pro­gram­mers.

Some of this behav­ior can be reha­bil­i­tat­ed with perlcritic and perltidy, but what about oth­er sins attrib­uted to Perl? Here are a few peren­ni­al favorites”:

Objects and Object-​Oriented Programming

Perl has a min­i­mal­ist object sys­tem based on earlier-​available lan­guage con­cepts like data struc­tures (often hash­es, which it has in com­mon with JavaScript), pack­ages, and sub­rou­tines. Since Perl 5’s release in 1994 much ver­bose OO code has been writ­ten using these tools.

The good news is that since 2007 we’ve had a sophis­ti­cat­ed metaobject-​protocol-​based lay­er on top of them called Moose, since 2010 a light­weight but forward-​compatible sys­tem called Moo, and a cou­ple of even tinier options as described in the Perl OO Tutorial. Waiting in the wings is Corinna, an effort to bring next-​generation object capa­bil­i­ties into the Perl core itself, and Object::Pad, a test­bed for some of the ideas in Corinna that you can use today in cur­rent code. (Really, please try it — the author needs feed­back!)

All this is to say that 99% of the time you nev­er need trou­ble your­self with bless, con­struc­tors, or writ­ing acces­sors for class or object attrib­ut­es. Smarter peo­ple than me have done the work for you, and you might even find a con­cept or three that you wish oth­er lan­guages had.

Contexts

There are two major ones: list and scalar. Another way to think of it is plur­al” vs. sin­gu­lar” in English, which is hope­ful­ly a thing you’re famil­iar with as you’re read­ing this blog.

Some func­tions in Perl act dif­fer­ent­ly depend­ing on whether the expect­ed return val­ue is a list or a scalar, and a func­tion will pro­vide a list or scalar con­text to its argu­ments. Mostly these act just as you would expect or would like them to, and you can find out how a func­tion behaves by read­ing its doc­u­men­ta­tion. Your own func­tions can behave like this too, but there’s usu­al­ly no need as both scalars and lists are auto­mat­i­cal­ly inter­pret­ed into lists.” Again, Perl’s DWIMmery at work.

Subroutine and Method Arguments

I’ve already writ­ten about this. Twice. And pre­sent­ed about it. Twice. The short ver­sion: Perl has sig­na­tures, but they’ve been con­sid­ered exper­i­men­tal for a while. In the mean­time, there are alter­na­tives on CPAN. You can even have type con­straints if you want.


I’ll leave you with this: Over the past month, Neil Bowers of the Perl Steering Council has been col­lect­ing quirks like these from Perl devel­op­ers. The PSC is review­ing this col­lec­tion for poten­tial doc­u­men­ta­tion fix­es, bug fix­es, fur­ther dis­cus­sion, etc. I would­n’t expect to see any fun­da­men­tal changes to the lan­guage out of this effort, but it’s a good sign that poten­tial­ly con­fus­ing fea­tures are being addressed. 

I pub­lish Perl sto­ries on this blog once a week, and it seems every time there’s at least one response on social media that amounts to, I hate Perl because of its weird syn­tax.” Or, It looks like line noise.” (Perl seems to have out­last­ed that one — when’s the last time you used an acoustic modem?) Or the quote attrib­uted to Keith Bostic: The only lan­guage that looks the same before and after RSA encryption.”

So let’s address, con­front, and demys­ti­fy this hate. What are these objec­tion­able syn­tac­ti­cal, noisy, pos­si­bly encrypt­ed bits? And why does Perl have them?

Regular expressions

Regular expres­sions, or reg­ex­ps, are not unique to Perl. JavaScript has them. Java has them. Python has them as well as anoth­er mod­ule that adds even more fea­tures. It’s hard to find a lan­guage that does­n’t have them, either native­ly or through the use of a library. It’s com­mon to want to search text using some kind of pat­tern, and reg­ex­ps pro­vide a fair­ly stan­dard­ized if terse mini-​language for doing so. There’s even a C‑based library called PCRE, or Perl Compatible Regular Expressions,” enabling many oth­er pieces of soft­ware to embed a reg­exp engine that’s inspired by (though not quite com­pat­i­ble) with Perl’s syntax.

Being itself inspired by Unix tools like grep, sed, and awk, Perl incor­po­rat­ed reg­u­lar expres­sions into the lan­guage as few oth­er lan­guages have, with bind­ing oper­a­tors of =~ and !~ enabling easy match­ing and sub­sti­tu­tions against expres­sions, and pre-​compilation of reg­ex­ps into their own type of val­ue. Perl then added the abil­i­ty to sep­a­rate reg­ex­ps by white­space to improve read­abil­i­ty, use dif­fer­ent delim­iters to avoid the leaning-​toothpick syn­drome of escap­ing slash (/) char­ac­ters with back­slash­es (\), and name your cap­ture groups and back­ref­er­ences when sub­sti­tut­ing or extract­ing strings.

All this is to say that Perl reg­u­lar expres­sions can be some of the most read­able and robust when used to their full poten­tial. Early on this helped cement Perl’s rep­u­ta­tion as a text-​processing pow­er­house, though the core of reg­ex­ps’ suc­cinct syn­tax can result in difficult-​to-​read code. Such inscrutable exam­ples can be found in any lan­guage that imple­ments reg­u­lar expres­sions; at least Perl offers the enhance­ments men­tioned above.

Sigils

Perl has three built-​in data types that enable you to build all oth­er data struc­tures no mat­ter how com­plex. Its vari­able names are always pre­ced­ed by a sig­il, which is just a fan­cy term for a sym­bol or punc­tu­a­tion mark.

  • A scalar con­tains a string of char­ac­ters, a num­ber, or a ref­er­ence to some­thing, and is pre­ced­ed with a $ (dol­lar sign).
  • An array is an ordered list of scalars begin­ning with an ele­ment num­bered 0 and is pre­ced­ed with a @ (at sign). 
  • A hash, or asso­cia­tive array, is an unordered col­lec­tion of scalars indexed by string keys and is pre­ced­ed with a % (per­cent sign).

So vari­able names $look @like %this. Individual ele­ments of arrays or hash­es are scalars, so they $look[0] $like{'this'}. (That’s the first ele­ment of the @look array count­ing from zero, and the ele­ment in the %like hash with a key of 'this'.)

Perl also has a con­cept of slices, or select­ed parts of an array or hash. A slice of an array looks like @this[1, 2, 3], and a slice of a hash looks like @that{'one', 'two', 'three'}. You could write it out long-​hand like ($this[1], $this[2], $this[3]) and ($that{'one'}, $that{'two'}, $that{'three'} but slices are much eas­i­er. Plus you can even spec­i­fy one or more ranges of ele­ments with the .. oper­a­tor, so @this[0 .. 9] would give you the first ten ele­ments of @this, or @this[0 .. 4, 6 .. 9] would give you nine with the one at index 5 miss­ing. Handy, that.

In oth­er words, the sig­il always tells you what you’re going to get. If it’s a sin­gle scalar val­ue, it’s pre­ced­ed with a $; if it’s a list of val­ues, it’s pre­ced­ed with a @; and if it’s a hash of key-​value pairs, it’s pre­ced­ed with a %. You nev­er have to be con­fused about the con­tents of a vari­able because the name will tell you what’s inside.

Data structures, anonymous values, and dereferencing

I men­tioned ear­li­er that you can build com­plex data struc­tures from Perl’s three built-​in data types. Constructing them with­out a lot of inter­me­di­ate vari­ables requires you to use things like:

  • lists, denot­ed between ( paren­the­ses )
  • anony­mous arrays, denot­ed between [ square brack­ets ]
  • and anony­mous hash­es, denot­ed between { curly braces }.

Given these tools you could build, say, a scalar ref­er­enc­ing an array of street address­es, each address being an anony­mous hash:

$addresses = [
  { 'name'    => 'John Doe',
    'address' => '123 Any Street',
    'city'    => 'Anytown',
    'state'   => 'TX',
  },
  { 'name'    => 'Mary Smith',
    'address' => '100 Other Avenue',
    'city'    => 'Whateverville',
    'state'   => 'PA',
  },
];

(The => is just a way to show cor­re­spon­dence between a hash key and its val­ue, and is just a fun­ny way to write a com­ma (,). And like some oth­er pro­gram­ming lan­guages, it’s OK to have trail­ing com­mas in a list as we do for the 'state' entries above; it makes it eas­i­er to add more entries later.)

Although I’ve nice­ly spaced out my exam­ple above, you can imag­ine a less socia­ble devel­op­er might cram every­thing togeth­er with­out any spaces or new­lines. Further, to extract a spe­cif­ic val­ue from this struc­ture this same per­son might write the fol­low­ing, mak­ing you count dol­lar signs one after anoth­er while read­ing right-​to-​left then left-to-right:

say $$addresses[1]{'name'};

We don’t have to do that, though; we can use arrows that look like -> to deref­er­ence our array and hash elements:

say $addresses->[1]->{'name'};

We can even use post­fix deref­er­enc­ing to pull a slice out of this struc­ture, which is just a fan­cy way of say­ing always read­ing left to right”:

say for $addresses->[1]->@{'name', 'city'};

Which prints out:

Mary Smith
Whateverville

Like I said above, the sig­il always tells you what you’re going to get. In this case, we got:

  • a sliced list of val­ues with the keys 'name' and 'city' out of…
  • an anony­mous hash that was itself the sec­ond ele­ment (count­ing from zero, so index of 1) ref­er­enced in…
  • an anony­mous array which was itself ref­er­enced by…
  • the scalar named $addresses.

That’s a mouth­ful, but com­pli­cat­ed data struc­tures often are. That’s why Perl pro­vides a Data Structures Cookbook as the perldsc doc­u­men­ta­tion page, a ref­er­ences tuto­r­i­al as the perlreftut page, and final­ly a detailed guide to ref­er­ences and nest­ed data struc­tures as the perlref page.

Special variables

Perl was also inspired by Unix com­mand shell lan­guages like the Bourne shell (sh) or Bourne-​again shell (bash), so it has many spe­cial vari­able names using punc­tu­a­tion. There’s @_ for the array of argu­ments passed to a sub­rou­tine, $$ for the process num­ber the cur­rent pro­gram is using in the oper­at­ing sys­tem, and so on. Some of these are so com­mon in Perl pro­grams they are writ­ten with­out com­men­tary, but for the oth­ers there is always the English mod­ule, enabling you to sub­sti­tute in friend­ly (or at least more awk-like) names.

With use English; at the top of your pro­gram, you can say:

All of these pre­de­fined vari­ables, punc­tu­a­tion and English names alike, are doc­u­ment­ed on the perlvar doc­u­men­ta­tion page.

The choice to use punc­tu­a­tion vari­ables or their English equiv­a­lents is up to the devel­op­er, and some have more famil­iar­i­ty with and assume their read­ers under­stand the punc­tu­a­tion vari­ety. Other less-​friendly devel­op­ers engage in code golf,” attempt­ing to express their pro­grams in as few key­strokes as possible.

To com­bat these and oth­er unso­cia­ble ten­den­cies, the perlstyle doc­u­men­ta­tion page admon­ish­es, Perl is designed to give you sev­er­al ways to do any­thing, so con­sid­er pick­ing the most read­able one.” Developers can (and should) also use the perlcritic tool and its includ­ed poli­cies to encour­age best prac­tices, such as pro­hibit­ing all but a few com­mon punc­tu­a­tion vari­ables.

Conclusion: Do you still hate Perl?

There are only two kinds of lan­guages: the ones peo­ple com­plain about and the ones nobody uses.

Bjarne Stroustrup, design­er of the C++ pro­gram­ming language

It’s easy to hate what you don’t under­stand. I hope that read­ing this arti­cle has helped you deci­pher some of Perl’s noisy” quirks as well as its fea­tures for increased read­abil­i­ty. Let me know in the com­ments if you’re hav­ing trou­ble grasp­ing any oth­er aspects of the lan­guage or its ecosys­tem, and I’ll do my best to address them in future posts.

A moose

The override key­word in Perl’s Moose object sys­tem is a nice bit of code-​as-​documentation since it explic­it­ly states that a giv­en method over­rides from its super­class. It also has a super key­word that can be used inside an override, call­ing the next most appro­pri­ate super­class method with the same argu­ments as the orig­i­nal method.”

The Moose doc­u­men­ta­tion then goes on to say, The same thing can be accom­plished with a nor­mal method call and the SUPER:: pseudo-​package; it is real­ly your choice.” So when should you use one and not the oth­er? I decid­ed to find out.

First I defined a sim­ple Moose super­class with a sin­gle method:

package Local::MyClass;

use Moose;

sub my_method {
    return blessed $_[0];
}

__PACKAGE__->meta->make_immutable();

1;

And then a pair of sub­class­es, one using Moose’s override key­word and one with a plain sub:

package Local::MyClass::MyChildOverride;

use Moose;
extends 'Local::MyClass';

override my_method => sub {
    my $self = shift;
    return 'child ' . super;
};

__PACKAGE__->meta->make_immutable();

1;
package Local::MyClass::MyChildPlain;

use Moose;
extends 'Local::MyClass';

sub my_method {
    my $self = shift;
    return 'child ' . $self->SUPER::my_method();
}

__PACKAGE__->meta->make_immutable();

1;

So far so good, and both can be called successfully:

$ perl -Ilib -MLocal::MyClass::MyChildPlain \
  -MLocal::MyClass::MyChildOverride \
  -E '$PREFIX = "Local::MyClass::MyChild";
  for ( qw(Plain Override) ) {
    $object = "$PREFIX$_"->new();
    say $object->my_method()
  }'
child Local::MyClass::MyChildPlain
child Local::MyClass::MyChildOverride

Let’s toss in a new wrin­kle, though. What if we for­got to define the method in the superclass?

package Local::MyClassNoMethod;

use Moose;

__PACKAGE__->meta->make_immutable();

1;

Both ways of call­ing the super­class’s method will bug out, of course, but unlike a plain over­ride Moose will actu­al­ly pre­vent you from useing the offend­ing sub­class dur­ing the BEGIN phase:

$ perl -Ilib -MLocal::MyClassNoMethod::MyChildOverride \
  -E ''
You cannot override 'my_method' because it has no super method at /Users/mgardner/.plenv/versions/5.34.0/lib/perl5/site_perl/5.34.0/darwin-2level/Moose/Exporter.pm line 419
	Moose::override('my_method', 'CODE(0x7fe5cb811a88)') called at lib/Local/MyClassNoMethod/MyChildOverride.pm line 9
	require Local/MyClassNoMethod/MyChildOverride.pm at -e line 0
	main::BEGIN at lib/Local/MyClassNoMethod/MyChildOverride.pm line 0
	eval {...} at lib/Local/MyClassNoMethod/MyChildOverride.pm line 0
Compilation failed in require.
BEGIN failed--compilation aborted.

With plain method over­rid­ing, you only get an error if you try to call the super­class’s method. If your over­rid­den method does­n’t do that, it’s per­fect­ly safe to define and call. It’s only if you use that SUPER:: pseudo-​package that things blow up at runtime:

$ perl -Ilib -MLocal::MyClassNoMethod::MyChildPlain \
  -E '$obj = Local::MyClassNoMethod::MyChildPlain->new();
  $obj->my_method()'
Can't locate object method "my_method" via package "Local::MyClassNoMethod::MyChildPlain" at lib/Local/MyClassNoMethod/MyChildPlain.pm line 8.

Note that none of this is caught at com­pile time. perl -c will hap­pi­ly com­pile all these class­es and sub­class­es with­out a peep:

$ find . -name '*.pm' -exec perl -c {} \;
./lib/Local/MyClass/MyChildPlain.pm syntax OK
./lib/Local/MyClass/MyChildOverride.pm syntax OK
./lib/Local/MyClassNoMethod/MyChildPlain.pm syntax OK
./lib/Local/MyClassNoMethod/MyChildOverride.pm syntax OK
./lib/Local/MyClass.pm syntax OK
./lib/Local/MyClassNoMethod.pm syntax OK

So what can we con­clude? Moose’s override is a good way of describ­ing your intent with a sub­class, and it will catch you out if you try to use it with­out a cor­re­spond­ing method in a super­class. It is a non-​standard key­word though, so syntax-​highlighting edi­tors and code analy­sis tools won’t rec­og­nize it unless taught. Further, if your sub­class method does­n’t call the same method in a super­class you could even­tu­al­ly get away with remov­ing the lat­ter if you use a plain sub.

I’ve cre­at­ed a small GitHub project with the sam­ple code from this arti­cle, includ­ing test scripts.

What do you think? Is override suit­able for your Moose projects, or are you sat­is­fied with plain sub? Let me know in the comments.

The DZone tech pub­lish­ing site select­ed me as their Editors’ Pick Contributor of the Month for June 2021! Here’s my (bless­ed­ly brief) accep­tance speech dur­ing their month­ly awards ceremony.

Unfortunately, they’ve just start­ed to de-​prioritize con­tent syn­di­cat­ed from else­where due to Google not index­ing it. Since every arti­cle has to go through a mod­er­a­tion and edit­ing process, this means that I may not be able to ful­fill my promise to post new Perl con­tent there every week. You can still find it here on phoenixtrap.com, of course. ☺️

In March I wrote The Perl debug­ger can be your super­pow­er, intro­duc­ing the step debug­ger as a bet­ter way to debug your Perl code rather than lit­ter­ing your source with tem­po­rary print state­ments or log­ging. I use the debug­ger all the time, and I’ve real­ized that some more tech­niques are worth covering.

Although I men­tioned a caveat when debug­ging web appli­ca­tions, our apps at work all adhere to the Perl Web Server Gateway Interface (PSGI) spec­i­fi­ca­tion and thus we can use tools like Test::WWW::Mechanize::PSGI or Plack::Test to run tests and debug­ging ses­sions in the same Perl process. (Mojolicious users can use some­thing like Test::Mojo for the same effect.)

To demon­strate, let’s get start­ed with some­thing like this which tests that a giv­en route (/say-hello) returns a cer­tain JSON struc­ture ({"message": "Hello world!"}):

#!/usr/bin/env perl

use Test::Most;
use Test::WWW::Mechanize::PSGI;
use JSON::MaybeXS;
use Local::MyApp; # name of app's main module

my $mech = Test::WWW::Mechanize::PSGI->new(
    # a Dancer2 app, so to_app returns a PSGI coderef
    app => Local::MyApp->to_app(),
);
$mech->get_ok('/say-hello');
lives_and {
    my $json = decode_json($mech->content);
    cmp_deeply( $json, {message => 'Hello world!'} );
} 'message is Hello world!';

done_testing;

All very fine and well, but what hap­pens if that route starts return­ing a dif­fer­ent mes­sage or worse, invalid out­put that caus­es decode_json to fail? Eventually, you’ll rewrite the test in the script to out­put the offend­ing con­tent when some­thing goes wrong, but right now you want to suss out the root cause.

Debuggers have the con­cept of break­points, which are flags that tell the debug­ger to stop at a cer­tain line of code and wait for instruc­tions. We can set them while run­ning the debug­ger with the b com­mand or con­tin­ue to a one-​time break­point with the c com­mand, or we can insert them into the code our­selves before run­ning it through the debug­ger in the first place.

Add this line right after the lives_and { line:

$DB::single = 1;

This sim­u­lates hav­ing typed the s com­mand in the debug­ger at that line, stop­ping exe­cu­tion at that point. Run our test with per­l’s -d option, and then type c to con­tin­ue to that breakpoint:

$ perl -d -Ilib t/test_psgi.t

Loading DB routines from perl5db.pl version 1.60
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

[Local::MyApp:7170] core @2021-07-06 07:33:22> Built config from files: /Users/mgardner/Projects/blog/myapp/config.yml /Users/mgardner/Projects/blog/myapp/environments/development.yml in (eval 310)[/Users/mgardner/.plenv/versions/5.34.0/lib/perl5/site_perl/5.34.0/Sub/Quote.pm:3] l. 910
Test2::API::CODE(0x7ffabea39ee8)(/Users/mgardner/.plenv/versions/5.34.0/lib/perl5/site_perl/5.34.0/Test2/API.pm:71):
71:	    INIT { eval 'END { test2_set_is_end() }; 1' or die [email protected] }

  DB<1> c

[...]
ok 1 - GET /say-hello
main::CODE(0x7f8069caf2c8)(t/test_psgi.t:14):
15:	    my $json = decode_json($mech->content);

  DB<1> 

From here we can exam­ine vari­ables, set oth­er break­points, or even exe­cute arbi­trary lines of code. Let’s see what became of that HTTP GET request:

  DB<1> x $mech->content

0  '{"error":"Undefined subroutine &Local::MyApp::build_frog called at lib/Local/MyApp.pm line 11.\\n"}'

  DB<2> 

Aha, some­thing has returned some dif­fer­ent JSON indi­cat­ing an error. Let’s look at the lines around (10−20) the offend­ing line (11):

  DB<2> f lib/Local/MyApp.pm

  DB<3> l 10-20

10:	        my $method = 'build_frog';
11:	        $method->();
12 	    }
13:	    catch ($e) {
14:	        send_as JSON => {error => $e};
15 	    }
16:	    send_as JSON => {message => 'Hello world!'};
17:	};
18
19 	sub build_frob {
20:	    return;

  DB<4>

Yep, a typo on line 11, and one that was­n’t caught at com­pile time since it’s gen­er­at­ed at runtime.

Just to be sure (and to demon­strate some oth­er cool debug­ger fea­tures), let’s set anoth­er break­point while in the debug­ger and then exer­cise that route again. Then we’ll check that $method vari­able against the list of avail­able meth­ods in the Local::MyApp package.

  DB<4> b 11

  DB<5> $mech->get('/say-hello')

[...]
Local::MyApp::CODE(0x7f8066f2db60)(lib/Local/MyApp.pm:11):
11:	        $method->();

  DB<<6>> x $method

0  'build_frog'

  DB<<7>> m Local::MyApp
any
app
body_parameters
build_frob
captures
config
content
[...]
  DB<<8>>

No doubt about it, that vari­able is being set incorrectly.

Quit out of the debug­ger with the q com­mand, make the fix (we prob­a­bly want errors to give some­thing oth­er than an HTTP 200 OK while we’re at it), and re-​run the test:

$ perl -Ilib t/test_psgi.t

[Local::MyApp:8277] core @2021-07-06 07:48:36> Built config from files: /Users/mgardner/Projects/blog/myapp/config.yml /Users/mgardner/Projects/blog/myapp/environments/development.yml in (eval 309) l. 910
Name "DB::single" used only once: possible typo at t/test_psgi.t line 13.
[...]
ok 1 - GET /say-hello
ok 2 - message is Hello world!
1..2

Note that warn­ing about leav­ing $DB::single in there. While harm­less, it’s a good reminder to remove such lines from your code so that they don’t sur­prise you or your team­mates dur­ing future debug­ging sessions.

And that’s it. Note that because we’re using PSGI, we were able to set break­points in our web app code itself and the debug­ger stopped there and enabled us to have a look around. And as you’ve seen, once you’re at a break­point you can switch to dif­fer­ent files, add/​remove more break­points, run arbi­trary code, and more. The perlde­bug doc­u­men­ta­tion page has all the details.

Happy debug­ging! For your ref­er­ence, here’s the full app mod­ule and test script used in this article:

MyApp.pm

package Local::MyApp;
use Dancer2;
use Feature::Compat::Try;

our $VERSION = '0.1';

get '/say-hello' => sub {
    try {
        no strict 'refs';
        my $method = 'build_frob';
        $method->();
    }
    catch ($e) {
        status 'error';
        send_as JSON => {error => $e};
    }
    send_as JSON => {message => 'Hello world!'};
};

sub build_frob {
    return;
}

true;

test_psgi.t

#!/usr/bin/env perl

use Test::Most;
use Test::WWW::Mechanize::PSGI;
use JSON::MaybeXS;
use Local::MyApp; # name of your app's main module goes here

my $mech = Test::WWW::Mechanize::PSGI->new(
    # a Dancer2 app, so to_app returns a PSGI coderef
    app => Local::MyApp->to_app(),
);
$mech->get_ok('/say-hello');
lives_and {
    my $json = decode_json($mech->content);
    cmp_deeply( $json, {message => 'Hello world!'} );
} 'message is Hello world!';

done_testing;

iceberg in body of water

We have a huge code­base of over 700,000 lines of Perl spread across a cou­ple dozen Git repos­i­to­ries at work. Sometimes refac­tor­ing is easy if the class­es and meth­ods involved are con­fined to one of those repos, but last week we want­ed to rename a method that was poten­tial­ly used across many of them with­out hav­ing to QA and launch so many changes. After get­ting some help from Dan Book and Ryan Voots on the #perl libera.chat IRC chan­nel, I arrived at the fol­low­ing solution.

First, if all you want to do is alias the new method call to the old while mak­ing the least amount of changes, you can just do this:

*new_method = \&old_method;

This takes advan­tage of Perl’s type­globs by assign­ing to the new method­’s name in the sym­bol table a ref­er­ence (indi­cat­ed by the \ char­ac­ter) to the old method. Methods are just sub­rou­tines in Perl, and although you don’t need the & char­ac­ter when call­ing one, you do need it if you’re pass­ing a sub­rou­tine as an argu­ment or cre­at­ing a ref­er­ence, as we’re doing above.

I want­ed to do a bit more, though. First, I want­ed to log the calls to the old method name so that I could track just how wide­ly it’s used and have a head start on renam­ing it else­where in our code­base. Also, I did­n’t want to fill our logs with those calls — we have enough noise in there already. And last­ly, I want­ed future calls to go direct­ly to the new method name with­out adding anoth­er stack frame when using caller or Carp.

With all that in mind, here’s the result:

sub old_method {
    warn 'old_method is deprecated';
    no warnings 'redefine';
    *old_method = \&new_method;
    goto &new_method;
}

sub new_method {
    # code from old_method goes here
}

Old (and not-​so-​old) hands at pro­gram­ming are prob­a­bly leap­ing out of their seats right now yelling, YOU’RE USING GOTO! GOTO IS CONSIDERED HARMFUL!” And they’re right, but this isn’t Dijkstra’s goto. From the Perl manual:

The goto &NAME form is quite dif­fer­ent from the oth­er forms of goto. In fact, it isn’t a goto in the nor­mal sense at all, and does­n’t have the stig­ma asso­ci­at­ed with oth­er gotos. Instead, it exits the cur­rent sub­rou­tine (los­ing any changes set by local) and imme­di­ate­ly calls in its place the named sub­rou­tine using the cur­rent val­ue of @_. […] After the goto, not even caller will be able to tell that this rou­tine was called first.

perl­func man­u­al page

Computer sci­en­tists call this tail call elim­i­na­tion. The bot­tom line is that this achieves our third goal above: imme­di­ate­ly jump­ing to the new method as if it were orig­i­nal­ly called.

The oth­er tricky bit is in the line before, when we’re redefin­ing old_method to point to new_method while we’re still inside old_method. (Yes, you can do this.) If you’re run­ning under use warnings (and we are, and you should), you first need to dis­able that warn­ing. Later calls to old_method will go straight to new_method with­out log­ging anything.

And that’s it. The next step after launch­ing this change is to add a sto­ry to our back­log to mon­i­tor our logs for calls to the old method, and grad­u­al­ly refac­tor our oth­er repos­i­to­ries. Then we can final­ly remove the old method wrapper.

jack skelington vinyl figure

Ten years ago Rudolf Winestock wrote The Lisp Curse, an essay that attempt[ed] to rec­on­cile the pow­er of the Lisp pro­gram­ming lan­guage with the inabil­i­ty of the Lisp com­mu­ni­ty to repro­duce their pre-AI Winter achievements.”

His con­clu­sion? The pow­er and expres­sive­ness of Lisp have con­spired to keep its devel­op­ers indi­vid­u­al­ly pro­duc­tive, but col­lec­tive­ly unable to orga­nize their work into com­plete, stan­dard­ized, well-​documented, ‑test­ed, and ‑main­tained pack­ages that they could coa­lesce into inter­op­er­a­ble and widely-​adopted solu­tions. Everything from object sys­tems to types to asyn­chro­nous non-​blocking pro­gram­ming and con­cur­ren­cy is up for grabs and has mul­ti­ple com­pet­ing implementations.

These social effects have doomed Lisp to also-​ran sta­tus in an indus­try where employ­ers much pre­fer that work­ers be fun­gi­ble, rather than max­i­mal­ly pro­duc­tive.” Free tool­ing sup­port has lagged; although Emacs can be hacked end­less­ly to do any­thing, there is no out-​of-​the-​box inte­grat­ed devel­op­ment envi­ron­ment or batteries-​included defaults to imme­di­ate­ly ease new pro­gram­mers into their job.

Does this all sound famil­iar to Perl developers?

Perl is renowned for its expres­sive capa­bil­i­ties, enshrined in the TIMTOWTDI (There Is More Than One Way To Do It) design prin­ci­ple. Stories abound of the pro­duc­tiv­i­ty achieved by Perl pro­gram­mers stitch­ing togeth­er mod­ules from CPAN with their own code. Select an object sys­tem (or don’t), maybe throw in an excep­tion han­dler (or don’t), and you too can have a code­base that fel­low devel­op­ers cri­tique for not fol­low­ing their favored tech­niques. Meanwhile, man­agers are strug­gling to fill the rest of the team with new pro­gram­mers look­ing for IDE sup­port and find­ing only a grab-​bag of Vim extensions.

But there’s hope.

Perl has start­ed incor­po­rat­ing fea­tures expect­ed of mod­ern pro­gram­ming lan­guages into its core while mak­ing room for fur­ther exper­i­men­ta­tion via CPAN. The Language Server Protocol (from Microsoft of all places!) has enabled Perl IDE fea­tures in text edi­tors to boost pro­duc­tiv­i­ty for new and expe­ri­enced devel­op­ers alike. And there’s a pilot Request For Comment process for fur­ther improvements.

These efforts point to a future where Perl’s expres­sive strength is mar­ried with sen­si­ble defaults and fea­tures with­out break­ing back­ward com­pat­i­bil­i­ty. Maybe the curse can be overcome.

black and white laptop

The fol­low­ing is adapt­ed from my light­ning talk Blogging Outside the Bubble” at last week’s Perl and Raku Conference in the Cloud 2021. You can watch the pre­sen­ta­tion and down­load the slides here. Also, a tip: most of this applies to any­one who wants to start a blog.

Let’s say you’re a Perl devel­op­er dis­traught at the con­tin­ued decline in usage and mind­share of your favorite language.

You know that you do good work and that your tools and tech­niques are sound, but the world out­side of Perl-​specific forums, soft­ware archives, social media groups, and IRC chan­nels regards it as anti­quat­ed, out-​of-​date, or worse, that IT epi­thet lega­cy. (And the new­er devel­op­ers haven’t even heard of IRC!)

Let’s say you’re wor­ried about your pro­fes­sion­al prospects both at your cur­rent employ­er and with pos­si­ble future employ­ers. Even though you know or can eas­i­ly be trained in oth­er lan­guages, Perl is still your favorite.

Let’s say you’re me.

What do you do?

Step 1: Get a blog

There are two basic types of blogs: stan­dard­ized for­mat and cus­tomiz­able. If you’re just start­ing and you want to spend more time writ­ing and less time fid­dling with tem­plates and soft­ware, choose stan­dard­ized. Here are some sites that enable you to pub­lish your work while get­ting out of your way and that have developer-​centric com­mu­ni­ties. Pick one and set up an account:

If you want more cus­tomiza­tion options, you could try:

  • WordPress.com (host­ed, but lets you change some things around)
  • GitHub Pages (good if you’re already used to col­lab­o­ra­tive soft­ware devel­op­ment there, but requires more set­up includ­ing blog gen­er­a­tion software)
  • Or your pre­ferred host­ing provider — look for ready-​to-​go blog­ging apps like WordPress

What did I choose? I set up WordPress on a shared plan at HostGator (full dis­clo­sure: I work there). They also offer easy man­aged WordPress host­ing for a bit more, but I like to tinker.

And yes, the WordPress soft­ware is based on PHP. Don’t sweat that it’s not Perl. PHP does­n’t have to lose” for Perl to win.”

Step 2: Write

Finding a top­ic to write about can seem hard, but it does­n’t have to be. The Perl (and Raku) Weekly Challenge pub­lish­es two new pro­gram­ming chal­lenges every week. Work on those and pub­lish your solu­tion along with commentary.

Or write about what­ev­er you’re work­ing on or would like to work on. Write about your favorite Perl mod­ule or fea­ture. It does­n’t mat­ter if some­one else wrote about it; you have a unique perspective.

Coming up with a pithy title for your posts may be hard­er — you want to be click­bait-y but hon­est, and you want to men­tion Perl so that search engines asso­ciate your posts with the topic.

The impor­tant thing to do is write some­thing. And length does­n’t mat­ter; one or two para­graphs is fine.

Step 3: Promote

Here’s the bad news: no one is going to find your blog posts on their own. You need to put them in front of read­ers where they already are.

This means post­ing links on social net­works like Twitter, Facebook, and LinkedIn. It means dis­cus­sion groups and #hash­tags (like #perl, #programming, #webdev, etc.) on those social net­works. It means news forums like Reddit and Hacker News. And it means post­ing inside and out­side of Perl-​specific groups. Here are a cou­ple of exam­ples of the latter:

This social pro­mo­tion might get tedious after a while, so look into plu­g­ins for your blog­ging plat­form and ser­vices like IFTTT and Zapier that will mon­i­tor your blog’s news feed and auto­mat­i­cal­ly post on your behalf.

Also, remem­ber when I said above that there were blog­ging sites with developer-​centric com­mu­ni­ties? Even if your main blog isn’t on one of them, set up accounts and cross-​post. I repost my arti­cles on Dev.to, DZone, and Medium; all of these offer ways to import posts from your main site. One caveat: their importers don’t seem to be very smart when it comes to source code, so you may need to do a bit of edit­ing and refor­mat­ting after import.

Lastly, I would be remiss if I did­n’t men­tion the Perl Weekly newslet­ter. Every Monday a fresh batch of Perl con­tent is sent to peo­ple’s inbox­es and you could be part of it. Contact edi­tor Gábor Szabó about pub­lish­ing links to your new blog.

Step 4: Repeat

Remember that con­sis­ten­cy builds trust from your audi­ence. Make time to write reg­u­lar­ly and pub­lish posts as often as you can man­age. I set a goal to pub­lish at least once a week and have kept up this pace since January of this year. You can often find new top­ics as you mon­i­tor and par­tic­i­pate in the social forums in which you’re pro­mot­ing your blog, espe­cial­ly in the com­ments. Even neg­a­tive com­ments can dri­ve new topics.

Did this arti­cle inspire you to start a blog? Do you have more ques­tions? Let me know in the com­ments below!

Just gave a five-​minute light­ning talk about blog­ging at The Perl and Raku Conference in the Cloud 2021. Here are the slides as a PDF.

Update

The con­fer­ence YouTube chan­nel post­ed the video of my talk (see below). I still need to get con­trol of my um“s and ah“s.

brown wooden arrow signed

A mentee asked me over the week­end if there was a way with­in a Mojolicious web appli­ca­tion to store the routes sep­a­rate­ly from the main appli­ca­tion class. Here’s one way. These instruc­tions assume you’re using Perl 5.34 and Mojolicious 9.19 (the lat­est as of this writ­ing) via the ter­mi­nal com­mand line on a Linux, Unix, or macOS sys­tem; make the appro­pri­ate changes if this does­n’t apply to you.

First, if you haven’t already, cre­ate your Mojolicious app at your shell prompt:

$ mojo generate app Local::RouteDemo
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/script
  [write] /Users/mgardner/Projects/blog/local_route_demo/script/local_route_demo
  [chmod] /Users/mgardner/Projects/blog/local_route_demo/script/local_route_demo 744
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/lib/Local
  [write] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo.pm
  [exist] /Users/mgardner/Projects/blog/local_route_demo
  [write] /Users/mgardner/Projects/blog/local_route_demo/local-route_demo.yml
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo/Controller
  [write] /Users/mgardner/Projects/blog/local_route_demo/lib/Local/RouteDemo/Controller/Example.pm
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/t
  [write] /Users/mgardner/Projects/blog/local_route_demo/t/basic.t
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/public
  [write] /Users/mgardner/Projects/blog/local_route_demo/public/index.html
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/templates/layouts
  [write] /Users/mgardner/Projects/blog/local_route_demo/templates/layouts/default.html.ep
  [mkdir] /Users/mgardner/Projects/blog/local_route_demo/templates/example
  [write] /Users/mgardner/Projects/blog/local_route_demo/templates/example/welcome.html.ep
$ cd local_route_demo

Create a new Perl mod­ule in your edi­tor for stor­ing your routes. Here we’re using Local::RouteDemo::Routes:

$ touch lib/Local/RouteDemo/Routes.pm
$ $EDITOR lib/Local/RouteDemo/Routes.pm

Make the mod­ule with a func­tion that will cre­ate the routes you want, giv­en a Mojolicious::Routes object. Here we’re just bring­ing over the default route cre­at­ed when we cre­at­ed our app:

package Local::RouteDemo::Routes;
use strict;
use warnings qw(all -experimental::signatures);
use feature 'signatures';
use Exporter 'import';
our @EXPORT_OK = qw(make_routes);

sub make_routes ($router) {
    $router->get('/')->to('Example#welcome');
    # add more routes here

    return;
}

1;

Adjust the appli­ca­tion class to load your new Routes mod­ule and call its export­ed function:

package Local::RouteDemo;
use Mojo::Base 'Mojolicious', -signatures;
use Local::RouteDemo::Routes 'make_routes';

# This method will run once at server start
sub startup ($self) {

    # Load configuration from config file
    my $config = $self->plugin('NotYAMLConfig');

    # Configure the application
    $self->secrets($config->{secrets});

    # Make routes
    make_routes($self->routes);

    return;
}

1;

Finally, run your tests and/​or man­u­al­ly test your routes to be sure every­thing works OK:

$ prove -vlr t
t/basic.t .. [2021-06-07 12:21:55.36917] [58779] [debug] [elVGykGVWlOt] GET "/"
[2021-06-07 12:21:55.36972] [58779] [debug] [elVGykGVWlOt] Routing to controller "Local::RouteDemo::Controller::Example" and action "welcome"
[2021-06-07 12:21:55.37137] [58779] [debug] [elVGykGVWlOt] Rendering template "example/welcome.html.ep"
[2021-06-07 12:21:55.37343] [58779] [debug] [elVGykGVWlOt] Rendering template "layouts/default.html.ep"
[2021-06-07 12:21:55.37495] [58779] [debug] [elVGykGVWlOt] 200 OK (0.005772s, 173.250/s)

ok 1 - GET /
ok 2 - 200 OK
ok 3 - content is similar
1..3
ok
All tests successful.
Files=1, Tests=3,  1 wallclock secs ( 0.02 usr  0.01 sys +  0.38 cusr  0.11 csys =  0.52 CPU)
Result: PASS
$ script/local_route_demo get /
[2021-06-07 12:22:29.55930] [58889] [debug] [f3YoaFhkwJ42] GET "/"
[2021-06-07 12:22:29.55990] [58889] [debug] [f3YoaFhkwJ42] Routing to controller "Local::RouteDemo::Controller::Example" and action "welcome"
[2021-06-07 12:22:29.56059] [58889] [debug] [f3YoaFhkwJ42] Rendering template "example/welcome.html.ep"
[2021-06-07 12:22:29.56269] [58889] [debug] [f3YoaFhkwJ42] Rendering template "layouts/default.html.ep"
[2021-06-07 12:22:29.56432] [58889] [debug] [f3YoaFhkwJ42] 200 OK (0.005004s, 199.840/s)
<!DOCTYPE html>
<html>
  <head><title>Welcome</title></head>
  <body><h2>Welcome to the Mojolicious real-time web framework!</h2>
<p>
  This page was generated from the template "templates/example/welcome.html.ep"
  and the layout "templates/layouts/default.html.ep",
  <a href="/">click here</a> to reload the page or
  <a href="/index.html">here</a> to move forward to a static page.
</p>
</body>
</html>

You can find a git repos­i­to­ry of this work on GitHub, and here’s a com­mit of all the changes made to the default Mojolicious appli­ca­tion so you can see the differences.

Update

Joel Berger from the Mojolicious project told me at The Perl and Raku Conference that it would be more idiomat­ic to use a Mojolicious plu­g­in rather than a plain mod­ule with an export, so here you go:

lib/Local/RouteDemo.pm:

package Local::RouteDemo;
use Mojo::Base 'Mojolicious', -signatures;

# This method will run once at server start
sub startup ($self) {

    # Load configuration from config file
    my $config = $self->plugin('NotYAMLConfig');

    # Configure the application
    $self->secrets($config->{secrets});

    # Add routes from plugin
    $self->plugin('Local::RouteDemo::Plugin::Routes');

    return;
}

1;

lib/Local/RouteDemo/Plugin/Routes.pm:

package Local::RouteDemo::Plugin::Routes;
use Mojo::Base 'Mojolicious::Plugin', -signatures;

sub register ($self, $app, $conf) {
    my $r = $app->routes;

    $r->get('/')->to('Example#welcome');
    # add more routes here

    return;
}

1;