[ Perl tips index ]
[ Subscribe to Perl tips ]
Over the next few tips, we'll be covering current best practices for programming Perl.
In 2005, Dr Damian Conway published the very popular "Perl Best Practices" book which details 256 "best practices" for Perl programming. While some of these "best practices" have been further improved on in the ensuing 5 years, many of them remain excellent practices for your coding. If you have not yet read this book, we strongly recommend that you do so! In this sequence of Perl tips we will cover a wide selection of current best practices, taking into account the ideas and modernisations that Perl has undergone..
use strict;
use warnings;
If you're not already using strict in all of your scripts, and using
warnings in almost all of your scripts, you have a lot to learn, and should
probably start with Conway's book.
Perl has had scalar filehandles and three-argument open for more than 10 years now:
# Opening a file for reading
open(my $in_fh, "<", $input_file) or die "Failed to open: $!";
# Reading from that filehandle
while(<$in_fh>) {
# do something with $_
}
close $in_fh;
# Opening a file for writing
open(my $out_fh, ">", $output_file) or die "Failed to open: $!";
# Printing to that filehandle
print {$fh} "This text will go into my file.";
close $out_fh;
Three-argument open treats the filename literally, which protects you from a number of potential security issues that are possible with two-argument open. Scalar filehandles - because they are just scalars - can be passed to subroutines, put in arrays, and used as values in hashes. Additionally, when the scalar goes out of scope before you close the file, Perl will automatically close the file for you. None of this is easy with package filehandles.
Ideally every organisation you work for, or project you work on, has a pre-established, formalised set of coding standards. While these may not be as current as you'd like, consistency is a good thing. If you don't have a coding standard, then now is a good time to develop one. Conway's book is a great starting place.
Perl 5.6.1 is almost 10 years old now (2001-Apr-08). Perl 5.8.2 is 7 years old (2003-Nov-05). Perl 5.10.0 is 3 years old (2007-Dec-18). Perl 5.8.9 is 2 years old (2008-Dec-14). Perl 5.10.1 is 1.5 years old (2009-Aug-22) Perl 5.12.2 is 4 months old (2010-Sep-06).
Upgrade! At the very, very least, use one of the Perl 5.8.x versions, but if you can, upgrade to either 5.10.1 or 5.12.2. Why? Because a whole lot of wonderful, new, awesome and *modern* features have been incorporated into Perl in the last few years.
To use the features of your modern version of Perl, just specify your minimum version:
use v5.10.1; # get all the things from Perl 5.10.1
By specifying any of the Perl 5.12 versions, strict is automatically turned
on by default. Thus this:
use v5.12.2;
is the same as saying:
use v5.12.2;
use strict;
This is a great improvement.
With Perl 5.10.0 we received a host of new features. Some of these are mentioned here:
say gives us print with an attached newline. Instead of:
print "Hello World!\n";
print "$_\n" foreach @list;
we can write:
use v5.10.0;
say "Hello World!";
say foreach @list;
it's shorter, neater, and gets rid of that ugly $_.
Consider this subroutine:
sub item_sale {
my ($product, $price) = @_;
$price ||= $product->cost;
...
}
This example is short, neat, and almost correct. But how do we signal that this item is being provided for free without changing the $product object? If we pass in zero, then that's a false value, so we're going to get the full product cost.
We could rewrite this to be:
sub item_sale {
my ($product, $price) = @_;
unless( defined($price) ) {
$price = $product->cost;
}
...
}
Or, in Perl 5.10.0 and above we can use defined-or. Defined-or works just like regular OR, except that it tests for whether the value is defined, rather than true.
use v5.10.0;
sub item_sale {
my ($product, $price) = @_;
$price //= $product->cost;
...
}
state allows us to create variables which remember their state. These are
like static variables in C. Imagine the following code to ensure that we
only show 100 images:
my $images_allowed = 100;
sub view_image {
die "Too many images" unless $images_allowed-- > 0;
...
}
As it is, other subroutines here could be used to change $images_allowed. To prevent that, we could wrap it into a closure:
{
my $images_allowed = 100;
sub view_image {
die "Too many images" unless $images_allowed-- > 0;
...
}
}
Or, we can use a state variable:
use v5.10.0;
sub view_image {
state $images_allowed = 100;
die "Too many images" unless $images_allowed-- > 0;
...
}
There's now a native switch for Perl, except that it's very, very cool.
use v5.10.0;
given ($has) {
when (/ninja/) { $ninjas++; }
when (/pirate/) { $pirates++; }
when (/robot/) { $robots++; }
when (@other) { $other_cool_things++; }
when (%interesting) { $interesting++; }
default { $boring++; }
}
This says smart match the value in $has. If it matches against any of the
first three regular expressions, increment that variable. Otherwise if it is an
element of @other increment $other_cool_things, otherwise if it is a key
in %interesting increment $interesting. If it matches none of these
comparisons, increment $boring.
The given-when can also be used with foreach:
use v5.10.0;
foreach (@input) {
when (/ninja/) { $ninjas++; }
when (/pirate/) { $pirates++; }
when (/robot/) { $robots++; }
when (@other) { $other_cool_things++; }
when (%interesting) { $interesting++; }
default { $boring++; }
}
given-when uses smart matching to work. Smart match allows us to compare things to determine if they match, in the most useful way possible:
use v5.10.0;
$foo ~~ undef; # is $foo undefined?
$foo ~~ @array; # is $foo in @array?
$foo ~~ %hash; # is $foo a key in %hash?
$foo ~~ $coderef; # does $coderef->($foo) return true?
$foo ~~ qr{$re}; # does $foo pattern match $re?
$foo ~~ $bar; # does $foo equal $bar?
There are many other best practices still to be covered. In our next tip we'll discuss exception handling, and how you can test a wide variety of Perl versions from your home directory.
[ Perl tips index ]
[ Subscribe to Perl tips ]
This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.
If you have any questions please don't hesitate to contact us:
| Email: | contact@perltraining.com.au |
| Phone: | 03 9354 6001 (Australia) |
| International: | +61 3 9354 6001 |
Copyright Perl Training Australia. Contact us at contact@perltraining.com.au