Why even care about old Perls?
Because there are large amounts of hidden Perl code running on old systems
Because you can face this very problem
Why not upgrade Perl?
Because of the potential impact (may be hard to estimate)
Because in some cases, you just can't do it
Currently working as a Perl expert at a big French ISP
Mission: "maintain" old code, write new programs
Platform: about 2000 servers
Heterogeneous (Debian, Red Hat, Solaris, Windows)
Many were installed years ago
Old systems mean old Perls
Perl 5.000 .. October 1994
Perl 5.001 .. March 1995
Perl 5.002 .. February 1996
Perl 5.003 .. June 1996
Perl 5.004 .. May 1997
Perl 5.005 .. July 1998
Perl 5.6 .. March 2000
Perl 5.8 .. July 2002
Perl 5.10 .. RSN? JBDNF?
Perl 5.12 .. JBTEOTU?
Language
version
syntax
features
Modules
version
features
availability
use 5.8
or require 5.8
Question the origin of this prerequisite
may have been added by a code generation tool, for example h2xs
may have been added on purpose by the author
Pertinence
estimate the pertinence of this prerequisite
if non pertinent, remove it
you win
maybe
if pertinent, you need to search further
Example
use 5.008006
is typical of h2xs
In most cases, can be removed
Keywords and operators
Functions
Strings
Regexps
Keywords and operators
our
(Perl 5.6)
state
(Perl 5.10)
//
(Perl 5.10 or 5.8+DOR)
our
Global variables used only once can be placed in a no strict
block
{ no strict 'vars'; $VERSION = '1.23'; @ISA = qw(Flower); }
Public variables can be declared with use vars
use vars qw($DEBUG);
Functions
open()
binmode()
open()
Very protean syntax with several different modes
Most part of it here since a long time
But two recent additions are commonly used
open()
open(FILEHANDLE, $path)
vs open my $fh, $path
Feature added with Perl 5.6
Syntax is valid in old Perls
But $fh
is not automatically affected
open()
open(FILEHANDLE, $path)
vs open my $fh, $path
Solution: manually create the file handle
use FileHandle; open my $fh = new FileHandle, $path or die $!;
or, even better, go the OO way
use FileHandle; my $fh = FileHandle->new($path) or die $!;
open()
3-arguments open()
open($fh, '<', $path);
Syntax introduced with Perl 5.6
open()
3-arguments open()
Unfortunately, the following obvious code doesn't work :-(
my @args = ('>', $path); open($fh, @args);
Simple solution: transform it back to 2-arguments open()
open($fh, '<'.$path);
Caveat: loosing the protecting feature
open()
3-arguments open()
Second solution: FileHandle
(since 5.002), or IO::File
(since 5.003_07)
use FileHandle; my $fh = FileHandle->new($path, $mode); # where $mode is ANSI mode: r, w, r+, etc
Strings
v-strings
qr//
v-strings
Syntax introduced with Perl 5.6
Any usage for anything other than version number should be verboten
Haven't encountered any v-strings yet
v-strings
Solution: get back to strings or floats
Pro: well-known method, used since years
Con: less reliable
Example:
if ($version > 2.034) { ... }
v-strings
Solution: use version.pm
(works with 5.005_04 and later,
core in 5.10)
Pro: object interface with overloaded operators
Con: doesn't provide much portability beyond 5.6
Example:
use version; my $vers1 = version->new("1.2.3"); my $vers2 = version->new("1.2.5"); if ($vers1 < $vers2) { ... }
v-strings
Solution: use Perl::Version
(pure Perl, works with at least 5.004)
Pro: classic object module, good for modifying versions
Con: must numify to compare versions
Example:
use Perl::Version; my $vers1 = Perl::Version->new("1.2.3"); my $vers2 = Perl::Version->new("1.2.5"); if ($vers1->numify < $vers2->numify) { ... }
qr//
Syntax introduced with Perl 5.005
Often seen in test suites
Typical use: like($result, qr/regexp/)
Can be safely replaced with a simple string with no functional risk
When used in actual code
...
Haven't seen the case yet :-)
But should be as safe as inside tests
Regexps
Assertions
Classes
Extended patterns
Assertions
\z
(Perl 5.006)
\Z
matches only at end of string, or before newline at the end
\z
matches only at end of string
Will be seen as a "z"
by Perl 5.004
Therefore must protect the use of this assertion
my $end = $] >= 5.005 ? "\\z" : "\\Z"; substr($path, 0, -$ignore) =~ s/X(?=X*$end)/$CHARS[int(rand($#CHARS))]/ge;
Classes
POSIX classes [:class:]
(Perl 5.6)
Solution: replace these by their explicit equivalent, see perlre
Unicode classes (Perl 5.6)
\x{263a} wide hex character \N{nom} named character
\pP Match P, named property. Use \p{Prop} for longer names. \X Match eXtended Unicode "combining character sequence", equivalent to (?:\PM\pM*) \C Match a single C char (octet) even under Unicode.
Abandon all hope
Extended patterns
(?#text)
(Perl 5.003)
(?imsx-imsx)
(Perl 5.003)
(?:pattern)
(Perl 5.003)
(?=pattern)
(Perl 5.003)
(?!pattern)
(Perl 5.003)
(?<=pattern)
(Perl 5.005)
(?<!pattern)
(Perl 5.005)
Extended patterns
(?>pattern)
(Perl 5.005, experimental)
(?(condition)yes-pattern|no-pattern)
(Perl 5.005, experimental)
(?{ code })
(Perl 5.005, experimental)
(??{ code })
(Perl 5.6, experimental)
Possible dependencies:
pragmas
core modules
warnings
It is the first cause of incompatibility with old Perls
However $^W
is available since Perl 5.0
...
warnings
It was the first cause of incompatibility with old Perls
JFDI: warnings-compat
$CPAN/S/SA/SAPER/warnings-compat-0.04.tar.gz
$ perl5.00405 -e 'use warnings; warnings::warnif "hello"' hello at -e line 1 $ perl5.00405 -e 'no warnings; warnings::warnif "hello"' $
warnings-compat
Several limitations, but it works
use warnings::register; { no warnings 'redefine'; ... } warnings::warnif "...";
Caveats:
Not lexical
Categories are not used
base
Introduced in Perl 5.005
Establish "is-a" relationships with base classes
But quite complex for just this aim
and therefore quite fragile
Plus, some P5Porters don't like it as well
This is a personal bias of course, but we're talking about
portability on older Perls, where this module isn't available :-)
base
Solution: replace it with the equivalent code
use base qw(Parse::Syslog);
becomes
use Parse::Syslog; { no strict; push @ISA, qw(Parse::Syslog); }
constant
Introduced in Perl 5.004
But its features have evolved
In particular, grouped declarations
use constant { PROTOCOL_NAME => "http", PROTOCOL_PORT => 80, PROTOCOL_TYPE => "stream", };
must be rewritten:
use constant PROTOCOL_NAME => "http"; use constant PROTOCOL_PORT => 80; use constant PROTOCOL_TYPE => "stream";
Important: the "core" is a moving target
Check the date and version of inclusion
Module::CoreList
, corelist
$ corelist Data::Dumper Data::Dumper was first released with perl 5.005
Also check availability on the CPAN
More and more modules are dual-lifed
CPAN modules are regularly integrated to the core
Core modules are regularly put on the CPAN on their own
Corified modules:
5.004 : CGI
, CPAN
5.005 : Test
5.6 : File::Temp
, Pod::Parser
, Term::ANSIColor
5.8 : Encode
, Filter::Simple
, Locale::Maketext
,
Scalar::Util
, List::Util
, Storable
, Test::More
5.10 : version
, CPANPLUS
and its numerous dependencies
(Archive::Tar
, IO::Zlib
, Module::Pluggable
)
CPANized modules:
2001 : Test::Harness
2002 : Safe
, ExtUtils::MakeMaker
2003 : Data::Dumper
2004 : XSLoader
2005 : Sys::Syslog
2006 : ExtUtils::Install
, threads
, threads::shared
, Exporter
2007 : B::Lint
, File::Path
(soon)
Core modules change as well
New features are added
Bugs are corrected
Can be updated independently of Perl
So do it!