Sei sulla pagina 1di 12

Perl Coding Guidelines

Version 1.0

Amit Roy
amitrupu@gmail.com
Perl Coding Guidelines

Index
1 Introduction.........................................................................................................2
2 Golden rules ........................................................................................................2
2.1 Change the #! line ........................................................................................2
2.2 Enable warning ............................................................................................2
2.3 Check the Perl version ..................................................................................3
2.4 Use comments and indentation to improve readability ...................................3
2.5 Use my and use strict ................................................................................3
2.6 Use Hungarian like notation for variable naming ...........................................4
2.7 Differentiate between numeric and string comparison ...................................4
2.8 Use {} for extracting variable name ................................................................4
2.9 Understanding scalar context of list ..............................................................5
2.10 The ".." list creation operator .........................................................................5
2.11 Use quote like operator wherever possible .....................................................5
2.12 defined, exists and meaning of truth .............................................................6
2.13 Use explicit item variables in foreach, while context ......................................6
2.14 Better use of regular expressions ..................................................................7
2.15 Use Data::Dumper for debugging complex data structures .............................7
2.16 All subroutine definitions should be clubbed together ...................................8
2.17 Pass reference to list in subroutine argument ................................................8
2.18 Type check for subroutine arguments ...........................................................9
2.19 Use Storable module for dump / restore object model ...................................9
2.20 Use warn and die for error handling ..............................................................9
2.21 Using built-in functions rather than system() ................................................9
2.22 Check status of system() call or `` ................................................................ 10
2.23 Use FileHandle module instead of *FILE globs ............................................. 10
2.24 Dont forget to return 1 at the end of package .............................................. 10
2.25 Understand difference between use and require .......................................... 10
2.26 Use Getopt package for command line parsing ............................................ 11
2.27 Use POD documentation ............................................................................. 11

Amit Roy 1
Perl Coding Guidelines

1 Introduction
Perl is a high-level scripting language with enormous syntax and semantic features. Perl
syntax can make a code very powerful but simultaneously unreadable, even to the
owner after a while.

This is why it is recommended to follow a guideline during Perl coding. This would help
to:
Improve readability of code
Maintain the code by multiple developers
Provide bug free support
Restructure or package the code in future

2 Golden rules

2.1 Change the #! line


People normally provides absolute path of Perl binary at the first line after #!, e.g.

#!/bin/perl

One should instead use /usr/local/bin/perl.

Still the problem persists if you want to use your custom Perl installation area. Then
you have to change this #! line with your Perl path. A better solution is to use

#!/bin/env perl

as the first line which automatically takes the Perl binary path from $path environment
variable. So now you dont have to change the Perl path in the code, but set your $path
environment variable so that your installation gets priority, i.e.

set path = (/software/ActivePerl/5.8/bin $path)


test.pl

2.2 Enable warning


Common mistakes in Perl coding can be easily avoided by enabling warning in Perl
code. One can enable warning by putting following line in the code.

use warnings;

Amit Roy 2
Perl Coding Guidelines

2.3 Check the Perl version


Perl has changed a lot from version 5.6. It is recommended to use latest version of Perl
in your code, at least 5.6 or more (e.g. 5.8). You can check the version by:

perl v

If your system has an old version of Perl, download latest version of Perl and use that as
instructed in 2.1.

You can also get the Perl version from within Perl code using built-in variable $],

print $].\n;

It is recommended to enable version checking in your code, by putting following lines in


your code.

my $VERSION = 5.006;
require $VERSION;

2.4 Use comments and indentation to improve readability


Use comments and proper indentation to improve the code readability, e.g.

#!/bin/env perl
use 5.008; # check version
use strict;
use warnings;

# Global variables
my ($gbCheckAll, $gbIsFull);


if (($gbCheckAll && $gbIsFul) {
# Do computation
my $nSum = $nItemA + $nItemB;

}

2.5 Use my and use strict


It is strictly recommended to developers to use my when declaring variables. If not
used this might result typo error, which will only arrive during run-time (if under some
conditional statement, it might show up at face of customer) and again very buggy.

$bIsFull = 1;
if ($bCheckAll && $bIsFul) { } # one l is missing

To ensure the use of my strictly in code (whenever he wants to declare a variable) and
catch above error, one can use use strict; in code.

Amit Roy 3
Perl Coding Guidelines

use strict;
my $bIsFull = 1;
if ($bCheckAll && $bIsFul) ( # will be caught at compilation time

}

2.6 Use Hungarian like notation for variable naming


Perl is a type-unsafe language. That means a variable is not associated with a type, and
one variable can hold integer at a time and string value at later point of time. So it
might be difficult for user to remember which type, a variable is indented to hold and
select specific operation (numeric or string) on that.

A better idea is to use Hungarian notation for variable naming, which will, by-name
specify the type of value it is holding. That is, the first character (which will be s, n,
b, l, h, p etc) will indicate the type. For example,

my $sName; # stores string


my $nAge; # stores integer
my $bCheck; # stores boolean i.e. 0 or 1 of integer range
my @lNameList = (); # list
my %hIdTable = (); # hash
my $pNameListRef = []; # list reference

Global variables can be again prefixed with g i.e. my gbExitOnError;

It is recommended that you initialize all global variables during declaration. Otherwise,
before reading you should be careful and use (!defined $g<VariableName>) to check if
no value is there.

2.7 Differentiate between numeric and string comparison


In Perl, comparison operator is different between number and string values. For,
numbers, the comparison operators are ==, !=, >, <, >= and <=, while for string values
they are eq, ne, gt, lt, ge and le. One should be careful to use this and should check the
first character of variable name, given following Hungarian notation.

print $sUserName. logged on. if ($sUserName eq Joe);


print Phone: $nPhoneNumber.\n unless ($nPhoneNumber == 0);

Note, non-string scalar (i.e. reference) comparison can be done using numeric
comparison operators.

2.8 Use {} for extracting variable name


Use {} to extract variable names at confusing context, e.g. concatenation etc.

my $sCompany = Self;
print ${sCompany}Systems; # not print $sCompanySystems;

Amit Roy 4
Perl Coding Guidelines

print @{ $pTable->{$sName} }; # pTable is a hash of list


print keys(%{ $pTab->{$sName} }); # hash of hash
print ${ $lIntRefList[$i] }; # not $$lIntRefList[$i]

Wherever the variable name is not clear from the context, use {}.

2.9 Understanding scalar context of list


Perl has context dependency in some cases. For example, if list is assigned in scalar
context it provides the size of the list. You have to be careful while using this.

my @lIntList = (1, 2, 3);


my $nListSize = @lIntList; # gives list size
my @lCopyList = @lIntList; # copies whole list

Recommendation is to use scalar() where you are trying to get list size. This will improve
readability.

my $nListSize = scalar(@lIntList);

2.10 The ".." list creation operator


The .. operator can be used to create a numeric list.

print 0..9; # prints 0123456789


# print the first 10 elements in an array
foreach (0..9) {
print $array[$_];
}

2.11 Use quote like operator wherever possible


Use quote like operator wherever possible. This removes coding effort and improves
readability.

my $sMessage = qq(My name is Joe. Im an engineer.);


my @lNameList = qw(tiger lion elephant);
my $pListRef = [qw{1 2 3 4}];
my $sMachineName = qx{uname -nodename}; # do not use ``
my $rFloatPattern = qw{[0-9]+(\.[0-9]+)?};

For multi-line message you can use,

my $sHelpMessage = <<EOD;

Usage: $0 [options] <files>

Options:
-help Shows help
-file <path> Take options from file
EOD
Print $sHelpMessage;

Amit Roy 5
Perl Coding Guidelines

2.12 defined, exists and meaning of truth


In Perl, meaning of true is different compared other languages. In Perl, the following
are false:
the number zero (0)
the empty string ("")
an undefined value (undef)

It is important to understand the process Perl goes through to test for truth.
First, if the value is not already a string, it is stringified. Strings remain as they
are.
If the string is "" or "0", it is considered as false.
This leads to the strange situation where the string "0.0" is TRUE.

But this is an unusual case. More commonly, confusion arises from the differences
between definedness, existence, and truth.

my $a = 0;
if ($a) { } # false
if (defined $a) { } # true
my %hash = (
a => 0,
b => 1,
c => 2
);
if ($hash{a}) { } # false because it is zero
if (exists $hash{d}) { } # false; no warning
if ($hash{d}) { } # false; produces warning with -w

Also note, you should use defined and exists where you are not sure enough about
the existence of the variable.

2.13 Use explicit item variables in foreach, while context


In foreach, while context, one can use $_ or simply ignore the item variable name.

foreach (keys(%hNameAgeTable)) {
print; # means print $_
print $hNameAgeTable{$_};
}
while (<$fFile>) {
print;
}

It is recommended to use variable name for better readability of code.

foreach my $sName (keys(%hNameAgeTable)) {


print $sName;
print $hNameAgeTable{$sName};
}
while (my $sLine = <$fFile>) {
print $sLine;
}

Amit Roy 6
Perl Coding Guidelines

2.14 Better use of regular expressions


One should use m{} and s{} explicitly when using regular expressions (regexp) in match
and substitution context.

# Verilog parsing snippet


my $rIdPat = qr{[a-z_][a-z0-9_]*}i;
while (defined $sBuffer) {
if ($sBuffer =~ m{^\s*
(wire|reg) \s+ ($rIdPat) \s*;\s* (.*) $}sx) {
my $sWireType = $1;
my $sWireName = $2;
$sBuffer = $3;
}
}

Important things to note:


Use s for muti-line regexp matching
Use x for extended regexp, which ignores white-space in regexp. Thus here
regexp can be multi-line and to denote white-space one has to use \s. This
improves readability.
Use $1, $2 to extract matched string parts
? can be used for non-greedy match

Use chomp() to trimming white-spaces.

while (my $sLine = <$pFile>) {


chomp($sLine);

}

2.15 Use Data::Dumper for debugging complex data structures


When you are creating complex data structure i.e. list of list or hash, hash of list or
hash or class object containing other class objects, it is hard to debug its value. A better
solution would be to use Data::Dumper module.

use Data::Dumper;
my $rStudentList = [
{
name => "joe",
roll => 2,
friendList => [
"martin",
"rob",
"pradip"
],
passYear => 1997
}
];
print Dumper($rStudentList);

Amit Roy 7
Perl Coding Guidelines

2.16 All subroutine definitions should be clubbed together


All subroutine definitions should be placed together in a file. This area should be
separated from the main code area where the subroutines are called. For example,

#!/bin/env perl
use 5.008; # check version
use strict;
use warnings;
use Getopt::Std;

## Global variables
my $gbExitOnError = 1;

## Main code
printBanner();
my $rCommandLineHash = parseCommandLine();
my $lFiles = readFiles($rCommandLineHash);
process($lFiles, $rCommandLineHash);

## Subroutine definitions

# printBanner prints the front banner


sub printBanner() { }

2.17 Pass reference to list in subroutine argument


One should be careful while passing a list to subroutine as argument value. If it is
passed simply as list, it will be concatenated to subroutine argument list i.e. @_. This is
ok when you are passing a single argument i.e. the list only. If you are passing multiple
arguments, to isolate an argument as list, one should pass reference to list. Same for
hash. For following Perl code,

use Data::Dumper;
my $sName = Joe;
my @lNameList = qw(Martin Pradip Kaushik);
printAll($sName, @lNameList, \@lNameList);
sub printAll() {
print Dumper(@_);
}

output will be:

$VAR1 = 'Joe';
$VAR2 = 'Martin'; # concatenated with @_
$VAR3 = 'Pradip'; # concatenated with @_
$VAR4 = 'Kaushik'; # concatenated with @_
$VAR5 = [ # can be isolated as list
'Martin',
'Pradip',
'Kaushik'
];

Amit Roy 8
Perl Coding Guidelines

2.18 Type check for subroutine arguments


One should put type checking on sub-routine arguments as below.

# sub-routine use
mySub("x", [qw{1 2 3 4}], { x => 5, y => 6 }, 7); # ok
mySub(1, [1], { 1 => 1 }); # ok
mySub(1, 1, 1); # compile-time error
# do not use &mySub()

# sub-routine definition
sub mySub($@%;$) {
my ($sName, $pListRef, $pHashRef, $sOptArg) = @_;
print $sName."@$pListRef".$pHashRef->{$sName};
defined $sOptArg && print $sOptArg;
}

2.19 Use Storable module for dump / restore object model


For dumping and restoring object model to/from file, one should use nstore and
retrieve functions of Perl module Storable.

use Storable qw(nstore retrieve);


nstore($pHash1, 'file1.store'); # binary dump
my $pHash2 = retrieve('file1.store'); # restore

2.20 Use warn and die for error handling


In code, one should use warn or die for any sort of error messaging. The benefit of
these is that they display the messages in STDERR and die automatically handles exit
mechanism for error case.

die Abnormal termination if ($bError); # prints file and line


# info along with
scalar(@ARGV) > 0 || die Usage: $0 <files >\n; # \n ignores
# file/line info

2.21 Using built-in functions rather than system()


Perl has many built-in functions which can be used instead of calling system(). Some
examples are:

system("chmod 755 myfile");


chmod 0755, "myfile"; # recommended
system("rm myfile");
unlink "myfile"; # recommended

The benefit of using the Perl functions is that they are less platform dependent and it
is easier to trap errors.

Amit Roy 9
Perl Coding Guidelines

2.22 Check status of system() call or ``


It is recommended to write a wrapper on system() or `` for other command executions.

sub systemWrapper($) {
my $sCommand = shift;
my $nStatus = system($sCommand);
die System command failed \n if ($nStatus != 0);
}
systemWrapper(ls -1);

2.23 Use FileHandle module instead of *FILE globs


Using FileHandle module is better than using old *FILE globs.

use FileHandle;
my $sFileName = qq{README.txt};
my $fFile = new FileHandle($sFileName);
die "Can't open file $sFileName ...\n" if (!defined $fFile);
while (my $sLine = <$fFile>) {
print $sLine;
}
# closes $fFile automatically

2.24 Dont forget to return 1 at the end of package


Do not forget to provide package statement at the beginning and return 1 at the end of
package file. Thus the structure of a Perl module (say XlsReader.pm) would be,

package MyXlsReader;

use strict;
use XlsCore;

# body

1;

2.25 Understand difference between use and require


Understand the difference between use and require. Both does the same thing, except
use is compile-time and require is run-time. So for built-in packages use use, and
use require, where
you need to derive the path of package
you want to import a package conditionally

#!/bin/env perl

use warnings;
use strict;

Amit Roy 10
Perl Coding Guidelines

use FileHandle;

my $sLibDir = qx{dirname $0};


push (@INC, $sLibDir/../lib);
require MyXlsReader;

if ($bNeedXlsWriter) {
require MyXlsWriter;

}

2.26 Use Getopt package for command line parsing


Use Getopt::Std and Getopt::Long Perl modules for command line parsing. This would
be a standard GNU mechanism of giving command line options.

2.27 Use POD documentation


It is recommended to do POD documentation of any Perl module you have developed
and intended to be used by other users.

Amit Roy 11

Potrebbero piacerti anche