This is a very old article. It has been imported from older blogging software, and the formatting, images, etc may have been lost. Some links may be broken. Some of the information may no longer be correct. Opinions expressed in this article may no longer be held.
Perl modules are not like dynamically loaded libraries in other programming languages. Thanks to the import
function, sub prototypes, symbol table hacking, parser hooks, magic like Devel-Declare, ties and other voodoo, Perl modules can shape and craft the flavour of Perl that is available to their caller. A practical example: Perl’s exception handling via eval
and $@
is weird, clunky and error-prone. But by loading TryCatch or Try::Tiny you get a clean syntax for catching exceptions that Just Works. You’re not just loading a library and using it at arm’s length; you’re changing the very syntax of Perl – locally, within your module.
(Aside: there are of course plenty of modules that don’t do any of this – say those that are designed to be used in an object-oriented fashion. Those are great too of course – different approaches are appropriate for solving different problems.)
Exception handling is not the only example. List::Util, Plack::Builder, Moose, MooseX::Method::Signatures, syntax (with its friends) and pretty much every module that uses Exporter or similar all fall into this broad category of modules that shape the flavour of Perl being used.
When starting a new script, or a new module, this is what we do. We add a bunch of use
statements to the top of the file to tweak Perl’s flavour to our liking. We make Perl a more suitable language for getting the job done; we turn a general purpose programming language into a domain-specific language suitable for our exact task. This will often begin with something like use 5.010; use strict; use warnings;
, but if you’re writing anything non-trivial, it’s likely that a bunch of other use
statements will join them.
Which brings me to Syntax::Collector. The idea of Syntax::Collector is that in a large project which spans multiple Perl modules and scripts, there are certain flavour of Perl that we wish to apply across all files. That might be use strict
and use warnings
to ensure good practice is followed, and might also include use Scalar::Util qw(blessed)
or use List::Util qw(first reduce)
or use Try::Tiny
. Syntax::Collector helps you capture that flavour in one module, and use that module in each script you write. Here’s an example:
package MyProject::Syntax;
our $VERSION = 1;
use Syntax::Collector -collect => '
use strict 0;
use warnings 0;
use true 0;
use feature 0 qw(say state switch);
no warnings 0 qw(void once uninitialized)
use Scalar::Util 1.23 qw(blessed);
use List::Util 0 qw(first reduce);
use Carp 0 qw(croak);
use Try::Tiny 0;
';
(Aside: you might be horrified that Syntax::Collector’s list of modules to import is a simple quoted string. Don’t worry; we don’t eval
it. It’s parsed and handled fairly sensibly. The purpose of using the Perl-like syntax within the string is to be friendly to people grepping through source code for use Some::Module
.)
Then in each file of the project, we just use MyProject::Syntax 1
and all the rest of that stuff is automatically imported. This not only has the advantage of reducing boiler-plate code, it can change the way you write Perl. Let’s imagine that we’re trying to find a parser that can handle HTML input:
my ($htmlparser) = grep { $_->does_accept('text/html') } @parsers;
That looks fine, and we might be happy with it, but if @parsers
is a long list, then it’s potentially pretty inefficient. After we’ve found the first HTML parser, we don’t want to keep grepping through the list. The first
function from List::Util would be much better:
my $htmlparser = first { $_->does_accept('text/html') } @parsers;
But if we’re working on a module, and this is the only time we need first
then we might sigh, ho hum, grep
will do. We’ll die
when we really should croak
. We’ll check defined ref
instead of blessed
. But with Syntax::Collector, and all these functions loaded up-front, we’re encouraged to use the right tool for the job.
Another advantage of Syntax::Collector is that it gives us a single place to declare all the project’s dependencies. Later on, if we want to reduce dependencies, we have a single place to peruse the list. If you notice that the only part if List::MoreUtils that you’re using is uniq
then you can write your own uniq
implementation (it’s a one-liner) and use that instead. And you don’t need to go through all your source files replacing references to List::MoreUtils, because the only reference is in your syntax module.
Syntax::Collector 0.004 is on CPAN.