The perlcritic tool is often your first defense against awk­ward, hard to read, error-​prone, or uncon­ven­tion­al con­structs in your code,” per its descrip­tion. It’s part of a class of pro­grams his­tor­i­cal­ly known as lin­ters, so-​called because like a clothes dry­er machine’s lint trap, they detect small errors with big effects.” (Another such lin­ter is perltidy, which I’ve ref­er­enced in the past.)

You can use perlcritic at the com­mand line, inte­grat­ed with your edi­tor, as a git pre-​commit hook, or (my pref­er­ence) as part of your author tests. It’s dri­ven by poli­cies, indi­vid­ual mod­ules that check your code against a par­tic­u­lar rec­om­men­da­tion, many of them from Damian Conway’s Perl Best Practices (2005). Those poli­cies, in turn, are enabled by PPI, a library that trans­forms Perl code into doc­u­ments that can be pro­gram­mat­i­cal­ly exam­ined and manip­u­lat­ed much like the Document Object Model (DOM) is used to pro­gram­mat­i­cal­ly access web pages.

perlcritic enables the fol­low­ing poli­cies by default unless you cus­tomize its con­fig­u­ra­tion or install more. These are just the gen­tle” (sever­i­ty lev­el 5) poli­cies, so con­sid­er them the bare min­i­mum in detect­ing bad prac­tices. The full set of includ­ed poli­cies goes much deep­er, ratch­et­ing up the sever­i­ty to stern,” harsh,” cru­el,” and bru­tal.” They’re fur­ther orga­nized accord­ing to themes so that you might selec­tive­ly review your code against issues like secu­ri­ty, main­te­nance, com­plex­i­ty, and bug prevention.

My favorite above is prob­a­bly ProhibitEvilModules. Aside from the col­or­ful name, a devel­op­ment team can use it to steer peo­ple towards an organization’s favored solu­tions rather than dep­re­cat­ed, bug­gy, unsup­port­ed, or inse­cure” ones. By default, it pro­hibits Class::ISA, Pod::Plainer, Shell, and Switch, but you should curate and con­fig­ure a list with­in your team.

Speaking of work­ing with­in a team, although perlcritic is meant to be a vital tool to ensure good prac­tices, it’s no sub­sti­tute for man­u­al peer code review. Those reviews can lead to the cre­ation or adop­tion of new auto­mat­ed poli­cies to save time and set­tle argu­ments, but such work should be done col­lab­o­ra­tive­ly after achiev­ing some kind of con­sen­sus. This is true whether you’re a team of employ­ees work­ing on pro­pri­etary soft­ware or a group of vol­un­teers devel­op­ing open source.

Of course, rea­son­able peo­ple can and do dis­agree over any of the includ­ed poli­cies, but as a rea­son­able per­son, you should have good rea­sons to dis­agree before you either con­fig­ure perlcritic appro­pri­ate­ly or selec­tive­ly and know­ing­ly bend the rules where required. Other CPAN authors have even pro­vid­ed their own addi­tions to perlcritic, so it’s worth search­ing CPAN under Perl::Critic::Policy::” for more exam­ples. In par­tic­u­lar, these community-​inspired poli­cies group a num­ber of rec­om­men­da­tions from Perl devel­op­ers on Internet Relay Chat (IRC).

Personally, although I adhere to my employer’s stan­dard­ized con­fig­u­ra­tion when test­ing and review­ing code, I like to run perlcritic on the bru­tal” set­ting before com­mit­ting my own. What do you pre­fer? Let me know in the com­ments below.


Cover image: Everyone’s a crit­ic — graifit­ti under Mancunian Way in Manchester” by Alex Pepperhill is licensed under CC BY-​ND 2.0

depth of field photography of brown tree logs

A recent Lobsters post laud­ing the virtues of AWK remind­ed me that although the lan­guage is pow­er­ful and lightning-​fast, I usu­al­ly find myself exceed­ing its capa­bil­i­ties and reach­ing for Perl instead. One such appli­ca­tion is ana­lyz­ing volu­mi­nous log files such as the ones gen­er­at­ed by this blog. Yes, WordPress has stats, but I’ve nev­er let rein­ven­tion of the wheel get in the way of a good pro­gram­ming exercise.

So I whipped this script up on Sunday night while watch­ing RuPaul’s Drag Race reruns. It pars­es my Apache web serv­er log files and reports on hits from week to week.

#!/usr/bin/env perl

use strict;
use warnings;
use Syntax::Construct 'operator-double-diamond';
use Regexp::Log::Common;
use DateTime::Format::HTTP;
use List::Util 1.33 'any';
use Number::Format 'format_number';

my $parser = Regexp::Log::Common->new(
    format  => ':extended',
    capture => [qw<req ts status>],
);
my @fields      = $parser->capture;
my $compiled_re = $parser->regexp;

my @skip_uri_patterns = qw<
  ^/+robots.txt
  [-\w]*sitemap[-\w]*.xml
  ^/+wp-
  /feed/?$
  ^/+?rest_route=
>;

my ( %count, %week_of );
while ( <<>> ) {
    my %log;
    @log{@fields} = /$compiled_re/;

    # only interested in successful or cached requests
    next unless $log{status} =~ /^2/ or $log{status} == 304;

    my ( $method, $uri, $protocol ) = split ' ', $log{req};
    next unless $method eq 'GET';
    next if any { $uri =~ $_ } @skip_uri_patterns;

    my $dt  = DateTime::Format::HTTP->parse_datetime( $log{ts} );
    my $key = sprintf '%u-%02u', $dt->week;

    # get first date of each week
    $week_of{$key} ||= $dt->date;
    $count{$key}++;
}

printf "Week of %s: % 10s\n", $week_of{$_}, format_number( $count{$_} )
  for sort keys %count;

Here’s some sam­ple output:

Week of 2021-07-31:      2,672
Week of 2021-08-02:     16,222
Week of 2021-08-09:     12,609
Week of 2021-08-16:     17,714
Week of 2021-08-23:     14,462
Week of 2021-08-30:     11,758
Week of 2021-09-06:     14,811
Week of 2021-09-13:        407

I first start­ed pro­to­typ­ing this on the com­mand line as if it were an awk one-​liner by using the perl -n and -a flags. The for­mer wraps code in a while loop over the <> dia­mond oper­a­tor”, pro­cess­ing each line from stan­dard input or files passed as argu­ments. The lat­ter splits the fields of the line into an array named @F. It looked some­thing like this while I was list­ing URIs (loca­tions on the website):

gunzip -c ~/logs/phoenixtrap.com-ssl_log-*.gz | \
perl -anE 'say $F[6]'

But once I real­ized I’d need to fil­ter out a bunch of URI pat­terns and do some aggre­ga­tion by date, I turned it into a script and turned to CPAN.

There I found Regexp::Log::Common and DateTime::Format::HTTP, which let me pull apart the Apache log for­mat and its time­stamp strings with­out hav­ing to write even more com­pli­cat­ed reg­u­lar expres­sions myself. (As not­ed above, this was already a wheel-​reinvention exer­cise; no need to com­pound that further.)

Regexp::Log::Common builds a com­piled reg­u­lar expres­sion based on the log for­mat and fields you’re inter­est­ed in, so that’s the con­struc­tor on lines 11 through 14. The expres­sion then returns those fields as a list, which I’m assign­ing to a hash slice with those field names as keys in line 29. I then skip over requests that aren’t suc­cess­ful or brows­er cache hits, skip over requests that don’t GET web pages or oth­er assets (e.g., POSTs to forms or updat­ing oth­er resources), and skip over the URI pat­terns men­tioned earlier.

(Those pat­terns are worth a men­tion: they include the robots.txt and sitemap XML files used by search engine index­ers, WordPress admin­is­tra­tion pages, files used by RSS news­read­ers sub­scribed to my blog, and routes used by the Jetpack WordPress add-​on. If you’re adapt­ing this for your site you might need to cus­tomize this list based on what soft­ware you use to run it.)

Lines 38 and 39 parse the time­stamp from the log into a DateTime object using DateTime::Format::HTTP and then build the key used to store the per-​week hit count. The last lines of the loop then grab the first date of each new week (assum­ing the log is in chrono­log­i­cal order) and incre­ment the count. Once fin­ished, lines 46 and 47 pro­vide a report sort­ed by week, dis­play­ing it as a friend­ly Week of date” and the hit counts aligned to the right with sprintf. Number::Format’s format_number func­tion dis­plays the totals with thou­sands separators.

Update: After this was ini­tial­ly pub­lished. astute read­er Chris McGowan not­ed that I had a bug where $log{status} was assigned the val­ue 304 with the = oper­a­tor rather than com­pared with ==. He also sug­gest­ed I use the double-​diamond <<>> oper­a­tor intro­duced in Perl v5.22.0 to avoid maliciously-​named files. Thanks, Chris!

Room for improvement

DateTime is a very pow­er­ful mod­ule but this comes at a price of speed and mem­o­ry. Something sim­pler like Date::WeekNumber should yield per­for­mance improve­ments, espe­cial­ly as my logs grow (here’s hop­ing). It requires a bit more man­u­al mas­sag­ing of the log dates to con­vert them into some­thing the mod­ule can use, though:

#!/usr/bin/env perl

use strict;
use warnings;
use Syntax::Construct qw<
  operator-double-diamond
  regex-named-capture-group
>;
use Regexp::Log::Common;
use Date::WeekNumber 'iso_week_number';
use List::Util 1.33 'any';
use Number::Format 'format_number';

my $parser = Regexp::Log::Common->new(
    format  => ':extended',
    capture => [qw<req ts status>],
);
my @fields      = $parser->capture;
my $compiled_re = $parser->regexp;

my @skip_uri_patterns = qw<
  ^/+robots.txt
  [-\w]*sitemap[-\w]*.xml
  ^/+wp-
  /feed/?$
  ^/+?rest_route=
>;

my %month = (
    Jan => '01',
    Feb => '02',
    Mar => '03',
    Apr => '04',
    May => '05',
    Jun => '06',
    Jul => '07',
    Aug => '08',
    Sep => '09',
    Oct => '10',
    Nov => '11',
    Dec => '12',
);

my ( %count, %week_of );
while ( <<>> ) {
    my %log;
    @log{@fields} = /$compiled_re/;

    # only interested in successful or cached requests
    next unless $log{status} =~ /^2/ or $log{status} == 304;

    my ( $method, $uri, $protocol ) = split ' ', $log{req};
    next unless $method eq 'GET';
    next if any { $uri =~ $_ } @skip_uri_patterns;

    # convert log timestamp to YYYY-MM-DD
    # for Date::WeekNumber
    $log{ts} =~ m!^
      (?<day>\d\d) /
      (?<month>...) /
      (?<year>\d{4}) : !x;
    my $date = "$+{year}-$month{ $+{month} }-$+{day}";

    my $week = iso_week_number($date);
    $week_of{$week} ||= $date;
    $count{$week}++;
}

printf "Week of %s: % 10s\n", $week_of{$_}, format_number( $count{$_} )
  for sort keys %count;

It looks almost the same as the first ver­sion, with the addi­tion of a hash to con­vert month names to num­bers and the actu­al con­ver­sion (using named reg­u­lar expres­sion cap­ture groups for read­abil­i­ty, using Syntax::Construct to check for that fea­ture). On my serv­er, this results in a ten- to eleven-​second sav­ings when pro­cess­ing two months of com­pressed logs.

What’s next? Pretty graphs? Drilling down to spe­cif­ic blog posts? Database stor­age for fur­ther queries and analy­sis? Perl and CPAN make it pos­si­ble to go far beyond what you can do with AWK. What would you add or change? Let me know in the comments.

woman in black tank top and blue denim jeans

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

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

Class::Struct

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

#!/usr/bin/env perl

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

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

package main;

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

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

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

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

And here’s the output:

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

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

Class::Accessor

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

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

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

#!/usr/bin/env perl

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

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

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

package main;

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

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

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

And here is its output:

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

Class::Tiny

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

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

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

#!/usr/bin/env perl

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

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

package main;

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

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

And its output:

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

Object::Tiny

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

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

Here’s an exam­ple script:

#!/usr/bin/env perl

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

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

package main;

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

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

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

And its output:

hello world
hello world

Add some speed with XS

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

Roles with Role::Tiny

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

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

#!/usr/bin/env perl

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

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

requires 'required_method';

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

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

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

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

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

package main;

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

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

$obj->foo();

And its output:

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

What’s your favorite?

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

close up of gear shift over black background

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

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

Here’s an example:

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

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

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

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

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

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

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

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

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

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

Introduction: The current state of play

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

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

Corinna, Object::Pad, and porting dbcritic

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

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

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

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

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

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

has $schema :reader :param = undef;

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

The ADJUST block for the $schema slot:

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

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

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

has %elements;

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

has @violations;

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

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

Issues

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

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

Conclusion: The future looks bright

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

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

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. 

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.

Lister Platz

As pre­vi­ous­ly writ­ten, I like list pro­cess­ing. Many com­put­ing prob­lems can be bro­ken down into trans­form­ing and fil­ter­ing lists, and Perl has got the fun­da­men­tals cov­ered with func­tions like map, grep, and sort. There is so much more you might want to do, though, and CPAN has a pletho­ra of list and array pro­cess­ing modules.

However, due to the vicis­si­tudes of Perl mod­ule main­te­nance, we have a sit­u­a­tion where it’s not clear at a glance where to turn when you’ve got a list that needs pro­cess­ing. So here’s anoth­er list: the list mod­ules of CPAN. Click through to dis­cov­er what func­tions they provide.

  • We’ve got List::Util which has been released as part of Perl since ver­sion 5.7.3.
  • We’ve got List::MoreUtils which has some func­tions which are named the same as Util but behave differently.
  • We’ve got List::SomeUtils which dupli­cates MoreUtils but with few­er dependencies.
  • We’ve got List::UtilsBy which MoreUtils has also cribbed some func­tions from.
  • We’ve got List::AllUtils which attempts to con­sol­i­date Util, SomeUtils, and ListBy but has some excep­tions to called mod­ules because of the afore­men­tioned dupli­ca­tion between Util and SomeUtils.
  • We’ve got List::Util::MaybeXS which helps with pure Perl fall­backs in case your ver­sion of Util is too old to have a cer­tain function.
  • We’ve got List::MoreUtils::XS which pro­vides (some?) faster ver­sions of MoreUtils’ func­tions (but you still have to use MoreUtils).
  • And last­ly, we have Util::Any which lets you import func­tions from Util, MoreUtils, and just for good mea­sure Scalar::Util, Hash::Util, String::Util, String::CamelCase, List::Pairwise, and Data::Dumper. But it has­n’t been updat­ed since 2016, so it does­n’t nec­es­sar­i­ly export the func­tions added to those mod­ules since then.

Am I miss­ing any­thing? Probably! But these are the ones most asso­ci­at­ed with being upstream on the CPAN River, so they (or the mod­ules they con­sol­i­date) have more projects depend­ing on them.

“CONFLICT” Scrabble tiles

If you’re writ­ing Perl that’s nev­er going to the Comprehensive Perl Archive Network (CPAN), heed this little-​known note on the Perl Authors Upload Server (PAUSE):

By con­ven­tion, the top-​level Local name­space should nev­er con­flict with any­thing on CPAN. This allows you to be con­fi­dent that the name you choose under Local isn’t going to con­flict with any­thing from the out­side world.

PAUSE: On The Naming of Modules

So, Local::MyModule, Local::App::MyApp, what­ev­er. This is also good advice for bespoke appli­ca­tions and libraries (the so-​called DarkPAN) you’re devel­op­ing in-​house. The last thing you need is to acci­den­tal­ly bring in (per­haps via depen­den­cies) a mod­ule that gets loaded instead of yours.