Perl_Part5

2

Click here to load reader

Transcript of Perl_Part5

Page 1: Perl_Part5

would in a normal Perl script. In theexample below a function being declared:

# Example 1sub log_error {print STDERR "Oops!\n";

}

This example will write the message“Oops!” to wherever the standard errorfile handle has been pointed. Thekeyword 'sub' denotes that a function isabout to be declared, next comes thename of the function, directly after is thecode block which is enclosed in the curlybraces. We will see later that there areseveral other arguments that can bepassed. This form will now be sufficientto make a practical error logging function.

# Example 2sub log_error {my @call = caller(1);print STDERR "Error: line U

$call [2]" . " of file $call U

[4]" . " in the function U

$call[3]\n";}

In example 2 we use the Perl function'caller' to give information on the callingsubroutine where the error occurred.Caller returns an array of data pertainingto where it was called. The most commonelements are listed below:

1. package2. file-name3. line number4. subroutine / function

Walter N

ovak,visipix.com

Items 2-4 should be familiar to you bynow, packages will be discussed in thefuture. More information on the 'caller'function can now be found by using the'perldoc -f caller' command from theshell prompt.

Invoking a user-definedfunctionAs with most (possibly all) things in Perl:“There is more than one way of doing it”,it follows then that there are numerousways of calling a user-defined function.

The three most common methods arelisted below. Each of these methods ofcalling the user defined functions has itsown implicit characteristics.

# Example 3log_error if $error == 1;

Example 3 calls the function 'log_error',provided that the function has beendeclared beforehand.

#Example 4my $error = 1;log_error() if $error;

Example 4 calls the function, regardlessof where in the script the function wasdeclared. The parenthesis indicate thatthe preceding word is a function. Theparenthesis are used to pass values to thefunction, this is covered later.

# Example 5&log_error if $error;

Example 5 calls the function, regardlessof whether it was defined before the codesection or not, using & is similar to using'$', '@' or '%', it clearly identifies thelabel as a function. However there areside-effects to using &, discussed later inthis article.

ParametersParameters make user-defined functionsvery powerful and flexible. Argumentscan be passed to user-defined functionsin the same fashion as the predefinedfunctions of Perl.

Values are copied to a function usingparenthesis and the contents of theparenthesis are passed using the defaultarray '@_'. This is the same variable thatcan be used throughout the program,however the value is stored elsewhere for

the duration of the function and its valuereturned at the end of the script. Thisconcept is called scope and is explainedin more detail later.

Using parameters to provide values to afunction enables the function to exist as astand alone piece of code:

# Example 6my $error_message;my $file = '/etc/passwd';

sub log_error {my @call = caller(1);print STDERR "Error at line U

$call[2] of file $call[1]" . U"in the function $call[4]\n";

print STDERR $error_message ifdefined($error_message);

}

if (-e $file) {$error_message = "$file is U

executable";log_error;

}

It seems comical to use this method,what would happen if you forgot to reset'$error_message', you'd give the wrongerror message which would be extremelymisleading putting you in the position ofdebugging your debug code. Modifyingthe previous example, we can give detailsas to the cause of an error as parametersto the argument:

# Example 7sub log_error {my $error_message = shift;my @call = caller(1);print STDERR "Error at line U

$call[2] of file $call[1]" ."in the function $call[4]\n";

print STDERR U

"$error_message\n" ifdefined($error_message);

}

my $file = '/dev/thermic_lance';

unless (-e $file) {log_error("$file doesn't U

exist");}

If you were particularly lazy you could

then create the function to check for theexistence of a file:

# Example 8sub exist_file {my $file = shift;unless (-e $file) {log_error("$file doesn't U

exist");}return 0;

}

This function in example 8 will callanother user defined function, the codefor which is shown previously. The codewill now give a standardized explanationof the error that occurred, in a standardformat using another user function toperform part of its task. The concept ofsplitting work among several user definedfunctions is called abstraction and hasmany benefits. An obvious one is that ifyou wanted to add a time-stamp then youwould only need to add the time stampcode once and all existing calls to'log_error' would reap the benefits.

Default ParametersA function does not mind how manyparameters are passed to it by default. Aswith standard arrays, if you try to accessan element that has no value, the valuereturned will be 'undef'. It is possible tomake Perl strictly adhere to set functionarguments as we will see.

# Example 9sub error_log {my $error_message = shift || U

'no message provided';my @call = caller(1);print STDERR "Error at line U

$call[2] of file $call[1]" . U"in the function $call[4]\n";print STDERR U

"$error_message\n";}

In example 9 if a parameter is not passed,then the default value reads 'no messageprovided', so the area returned could be:

Error at line 20 of file U

script.pl in the function U

test no message provided

The '||' operator is usually seen in condi-tional operators but in Perl it's equally at

5756 September 2002 www.linux-magazine.com www.linux-magazine.com September 2002

User defined functions are aninvaluable development toolenabling sections of code to be

reused many times. Shrewd use of userfunctions can create generic functionsthat reduce repetition of code whilstincreasing legibility and maintainability.

FunctionsA function is a collection of statementsthat can be grouped together to perform asingle task. The function can containnumerous calls to other perl functions oruser defined functions, including itself.This allows functions to act as black-boxes that can be used without theknowledge of how it operates.We declare a function by specifying itsname and listing the statements as we

Perl tutorialPROGRAMMING PROGRAMMINGPerl tutorial

In this month’ article we examine how to create user defined functions, test and apply the finished functions in several

separate scripts by creating libraries. BY FRANK FISH

Perl: Part 5

Thinking in Line Noise

Page 2: Perl_Part5

Fictional Place, Some Town','jdoe!john doe,Flat 184A 23rdUStreet, Some City','!bad line', 'another bad U

line.');

for (@lines) {my $index = '';

# pass the line and a U

reference to index.my $status = get_index($_,U\$index);print "The line '$_' has an U

index $index\n" if $status U

== 1;}

Example 11 will find the indexes for anarray of items and return a status for eachline, this status can then be used todecide if it is possible to continue withthe process.

It is worth noting that by default Perlfunctions will return the value from thelast statement in a function. It is notuncommon to see subroutines that don'thave 'return …' as the last line but rathera variable, function or value by itself justbefore the function declaration ends:while it is only necessary to use a returnvalue to explicitly leave a subroutineearly it is good form to explicitly give a'return' statement.

# Example 12

sub get_index($$) {my ($line, $index) = @_; U

my $status = 0;

if ($line =~ /^(\w+)!/ && $1 U

ne '' ){$$index = $1;

$status = 1;} else {log_error("No index.on line: U

$_\n");}$status;

}

Something greatly frowned upon in someprogramming disciplines is having morethan one exit point to a function. SincePerl acts as both a programming as wellas a scripting language the popularinterpretation of this rule is to bend it and

use the scripting ethos of “Exit early”.Example 13, be;ow, is the “Exit Early”

programming style.

# Example 13sub circ_area {my $radius = shift or return U

0;my $PI = 2.14;my $area = $PI * $radius * U

$radius;return $area;

}

It is a foregone conclusion that a radius ofzero will produce an area of zero, sorather than calculate this result as we didbefore, we return the result immediately.Since the rules of geometry are unlikelyto change in the working life of this code(and perhaps even before Perl 6 isreleased) such an action can hardly beseen as cavalier.

We can return half-way through anassignment due to two key features ofPerl. The 'or' operator has a greaterprecedence than the assignment operator,and more importantly Perl is a tolerant,stoic and syntactically gifted language.

ScopeIn example 6, we called a function and itaccessed a variable declared outside ofthe function

We assigned a particular message tothe variable '$error_message' and thiswas used in the function 'log_error'.

The variable we used is called a globalvariable, that is to say its name can beused anywhere and its value can be reador written to from anywhere within theprogram. The very fact that globals canbe altered from anywhere is the biggestargument against using them, they leadto messy un-maintainable code and areconsidered a bad thing.

#Example 15 (Does not compile)#!/usr/bin/perluse strict;use warnings;

my $global = 3;

sub functionX {my $private = 4;

print "global is $global\n";print "private is $private\n";

}

functionX;

print "global is $global\n";

# This line will fail as# $private doesn't exist# outside of the function# called functionX.print "private is $private\n";

Use of global variables is best avoided,and should only be used to declare anyconstant values that will remain for theduration of the program. Better, eventhen, to make use of the fact thatfunctions are always global, so no onecan revise the code and knock out aglobal variable:

sub PI(){ 3.14 }

Even using functions to make constants itis wise to pass the values as parametersinto the function, in case the function isplaced directly into another script, wherethe constant has not been passed. Anyfunction that can stand alone, can be unittested, and its functionality vouched for.

My, Our and LocalThere are three different ways to declare avariable in Perl, each affecting differentaspects of the scope. As a rule 'my' isalways used, failure to use 'our' or 'local'in the correct manner is considered anunforgivable sin.

'my' is the safest variety to use, thiscreates a variable and destroys it when itis no longer referred to, using the Perlgarbage collection.

Any variable declared using 'my'within a scope ( a looping structure orcode block ) exists only when that scopeis called and its value is then reset afterthe iteration.

{my $v = 1; # $v is 1;print "$v\n" # $v is 1;

} # $v no longer exists.

This can be especially useful in nestedloops where the inner variable is eachtime automatically initialized.

for my $x ( 0..9 ) {my $y = 0;print "Coordinate U

( $x, $y )\n" while $y++ < 3;}

'local' hi-jacks the value of a globalvariable, for the duration of its scope.This occurs at runtime rather than atcompile time and is referred to asdynamic scope.

my $v = 5; {local $v = 1; # $v is 1;print "$v\n" # $v is 1;

} # $v is 5 again.

As a rule 'local' should be avoided inpreference to 'my'. It is primarily used toalter global variables for short spaces oftime. Even then it is worth noting thatany function calls made within this scopewill also use the locally set value. If indoubt consult 'perldoc -f local' butremember 'my' is almost always whatyou want.

'our' allows the use of a variable withinthe lexical scope without initializing thevalue. 'our' becomes useful when wemake packages, which we will investigatein the future.

Function OdditiesIt is possible to establish a required setof values that the function must receiveor make it fail to compile and exit with aruntime exception. This can be desirablein some cases and allows greaterfreedom in our use of user-definedfunctions.

We can declare the prototypes at thestart of the code and then define the codeblock later in the program, in case wewish to use the extra features of prototyp-

5958 September 2002 www.linux-magazine.com www.linux-magazine.com September 2002

home in ordinary lines of code. It has alow order of precedence.

Many Happy returnsAll functions return a value. The valuethat a function returns can be the resultsof an operation or a status flag to showsuccess or failure of an operation.

The following example shows theresults of an operation:

# Example 10

sub circ_area {my $radius = shift || 0;my $PI = 2.14;my $area = $PI * $radius * U

$radius;return $area;

}

my $radius = 3;my $area = circ_area($radius);print "Area of a circle U

$radius in radius is $area\n";

Will be interpreted as “Set $radius to thevalue of the next element of the array@_, if there are no more values set thevalue to 'no message provided'.

The results of the user defined functionare returned directly, the essence of thefunction is to return the data.

In large systems a function return valueis used to convey success or failure of thefunction, this is extremely useful in tasksthat use many sections.

# Example 11

sub get_index($$) {my ($line, $index) = @_;my $status = 0;

if ($line =~ /^(\w+)!/ && $1 U

ne '' ){$$index = $1;$status = 1;

}else {log_error("No index on line: U

$_\n");}

return $status;}

my @lines = ('fred!fred bloggs, 12 U

M-J. Dominus' excellent website:perl.plover.com/FAQs/Namespaces.htmlperl.plover.com/local.html

Online References

keyword value name

my scoped scoped

local scoped global

our global scoped

VARIABLES IN PERL

Perl tutorialPROGRAMMING PROGRAMMINGPerl tutorial

ing to increase legibility of the code orforce certain uses.

sub foo; # Forward declaration.Usub foo(); # Prototype.

Using '&' does allow a programmer tooverrule any prototyping on a function. Afull description of prototyping with itsstrengths and weaknesses (Perl is after alla weakly typed language) will appear inthe future.

sub debugm($) {print STDERR "\n\n****\n$_U[0]\n***\n\n";

}

# Automatically uses $_debugm;

# This only prints the first# parameter but ignores the# function prototype.&debugm('beware','of this');

Perl DocumentationPerl has a wealth of good documentationcoming with the standard distribution, Itcovers every aspect of the Perl languageand is viewed using your computersystem’s default pager program. Thepages of Perldoc resemble the man pagesin that they cite examples of use and givepertinant advice.

There are a great many parts to the Perldocumentation. To list the categoriesavailable, type the following command atthe shell prompt:

perldoc perl

This then displays a page which has twocolumns. The left hand column lists themnemonic title while the right columnshows a description of the topic:

Perlsyn Perl syntaxPerldata Perl data structuresPerlop Perl operators and

precedencePerlsub Perl subroutines

Simply type perldoc and the mnemonicfor that subject on the command line:

perldoc perlsyn

This shows the Perl syntax information.■Perl docs: perldoc perlfunc

Further Reading