Vous êtes sur la page 1sur 8

Activity : Subioutines

Objectives:
Learn how to recycle block of codes.
Learn how to declare and create subroutines in Perl
Concepts
You have already seen and used some of the built-in system functions, such as chomp, reverse,
print and so on. But, as other languages do, Perl has the ability to make subroutines, which are user-
defined functions. These let us recycle one chunk of code many times in one program. The name of a
subroutine is another Perl identifier (letters, digits, and underscores, but it cannot start with a digit) with
a sometimes-optional ampersand (&) in front. There is a rule about when you can omit the ampersand
and when you cannot.
Defining a Subroutine
1. Use the keyword sub.
2. Follow the keyword sub with the name of the subroutine (without ampersand)
3. Specify the opening and closing curly braces that will signify the body of the subroutine
Table 4.1:
sub myfunc {
$n += 1; #Global variable $n
Print hello, student number $n!\n;
}

Invoking a Subroutine
Invoke a subroutine from within any expression by using the subroutine name with the
ampersand.
Table 4.2:
$myfunc; # says hello, student number 1!
$myfunc; # says hello, student number 2!
$myfunc; # says hello, student number 3!
Most often, we refer to the invocation as simply calling the subroutine.
Return Values
The subroutine is always invoked as part of an expression, even if the result of the expression is
not being used. Many times, you will call a subroutine and actually do something with the result. This
means that you will be paying attention to the return value of the subroutine. All Perl subroutines have
a return value there is no distinction between those that return values and those that do not. Not all
Perl subroutines have a useful return value, however.
Since all Perl subroutines can be called in a way that needs a return value, it would be a bit
wasteful to have to declare special syntax to return a particular value for the majority of the cases. As
Perl is chugging along in a subroutine, it is calculating values as part of its series of actions. Whatever
calculation is last performed in a subroutine is automatically also the return value.
Table 4.3:
sub sum {
print Hey, you called the sum subroutine!\n;
$x+ $y; # this is the return value of the sum subroutine
}

The last expression evaluated in the body of this subroutine is the sum of $x and $y, so the sum of $x
and $y will be the return value.
Table 4.4:
$x = 3;
$y = 4;
$result = ∑
print \$result is $result.\n;
$prod = 3 * ∑
print \$prod is $prod.\n;

Table 4.5: Suppose you added another line to the end of the sum subroutine:
sub sum {
print Hey, you called the sum subroutine!\n;
$x+ $y; # this is the return value of the sum subroutine
print Hey, I am returning a value now!\n;
}
In this example, the last expression evaluated is not the addition; it is the print statement. It return value
will normally be 1, meaning printing was successful, but that is not the return value you actually
wanted. So be careful when adding additional code to a subroutine, since the last expression evaluated
will be the return value.

The last expression evaluated really means the last expression evaluated, rather than the last
line of text. For example, the subroutine below returns the larger value of $x or $y;
Table 4.6:
sub larger {
if($x > $y){
$x;
}
else {
$y;
}
}
The last expression evaluated is either $x or $y, so the value of one of those variables becomes the
return value.

Arguments
The last subroutine (larger) would be much more useful if it did not force you to use the global
variables $y and $y.
Luckily, Perl has subroutine arguments. To pass an argument list to the subroutine, simply place
the list expression, in parentheses, after the subroutine invocation, like:
$n = &max(10,15); # this subroutine call has two parameters

The list is passed to the subroutine; that is, it is made available for the subroutine to use however it
needs to. Of course, you have to store this list somewhere, so Perl automatically stores the parameter
list (another name for the argument list) in the special array variable named @_ for the duration of the
subroutine. The subroutine can access this variable to determine both the number of arguments and
the value of those arguments.

This means that the first subroutine parameter is stored in $_[0], the second one is stored in $_[1] and
so on. But and here is an important note these variables have nothing whatsoever to do with the $_
variable. It is just that the parameter list must be stored into some array variable for the subroutine to
use it and Perl uses the array @_ for this purpose.
Table 4.7:
sub max {
if($_[0] > $_[1]){
$_[0];
}
else {
$_[1];
}
}
There is another problem with the subroutine declared above. The name &max is nice and short but it
does not remind us that this subroutine works properly only if called with exactly two parameters:

Excess parameters are ignored since the subroutine never looks at $_[2], Perl does not care whether
there is something in there or not.

And insufficient parameters are also ignored you simply get undef if you look beyond the end of the
@_array, as with any other array.

The @_ variable is private to the subroutine; if there is a global value in @_, it is saved away before the
subroutine is invoked and restored to its previous value upon return from the subroutine. This also
means that a subroutine can pass arguments to another subroutine without fear of losing its own @_
variable the nested subroutine invocation gets its own @_ in the say way.

Private Variables in Subroutines
By default, all variables in Perl are global variables; that is, they are accessible from every part of
the program. But you can create private variables called lexical variables at any time with the my
operator.


Table 4.9:
sub max {
my($m, $n); # new, private variables for this block
($m, $n) = @_; # give names to the parameters
if($m > $n){ $m } else { $n }
}
The variables $m,$n are private (or scoped) to the enclosing block; any other $m and $n is
totally unaffected by these two.
No other code can access or modify these private variables

Variable-Length Parameter List
Unlike many traditional programming languages, which require every subroutine to be strictly
typed (that is, to permit only certain, predefined number of parameters of predefined types), Perl
subroutines are given parameter list of arbitrary length.

Of course, the subroutine can easily check that it has the right number of arguments by
examining the @_ array.
Table 4.10:
sub max {
if(@_ != 2){
print "WARNING! $max should get exactly two arguments!\n"
}
# continue as before ...
.
.
.
}

Notes on Lexical (my) Variables

Those lexical variables can actually be used in any block, not merely in a subroutines block. For
example, they can be used in the block of an if, while or foreach:
Table 4.11:
foreach (1..10){
my($square) = $_ * $_; # private variables in this loop
print "$_ squared is $square. \n";
}

The variable $square is private to the enclosing block; in this case, thats the block of the foreach
loop.
One important concept is that the scope of a lexical variables name is limited to the smallest
enclosing block or file

Note also that the my operator does not change the context of an assignment:

Table 4.12:
my($num) = @_; # list context, same as ($num) = @_;
my $num = @_; # scalar context, same as $num = @_;

When reading code like this, you can always tell the context of the assignment by seeing what the
context would be without the word my.

So long as we were discussing using my( ) with parentheses, it is worth remembering that without the
parentheses, my only declares a single lexical variable:
my $fred, $barney; # WRONG! Fails to declare $barney
my($fred, $barney); # declares both
Of course, you can use my to create new, private arrays as well:
my @phone_number;
A new variable will start out empty undef for scalars or the empty list for arrays.

The use strcit Pragma
Perl tends to be a pretty permissive language. Sometimes you want Perl to impose a little
discipline; that can be arranged with the use strict pragma.

A pragma is a hint to a compiler, telling it something about the code. In this case, the use strict
pragma tells Perls internal compiler that it should enforce some good programming rules for the rest of
this block or source file.

Why would this be important? Well imagine that you are composing your program and you type
a line like this one:
$bamm_bamm = 3; # Perl creates that variable automatically

Now, you keep typing for a while. After that line has scrolled off the top of the screen, you type this line
to increment the variable:
$bammbamm += 1; # Ooops!

Since Perl sees a new variable name, it creates a new variable and increments that one. If you
are lucky and smart, you have turned on warnings and Perl can tell you that you used one or both of
those global variable names only a single time in your program.

To tell Perl that you are ready to more restrictive, put the use strict pragma at the top of your
program (or in any block of file where you want to enforce these rules):

use strict; # Enforce some good programming rules
Now, among other restrictions, Perl will insist that you declare every new variable, usually done with
my. If you try to spell it the other way, Perl can complain that you have not declared any variable called
$bammbamm, so your mistake is automatically caught at compile time.

The return Operator
The return operator immediately returns a value from a subroutine:
Table 4.13:
my @names = wq/ fred barney betty dino wilma pebbles bamm-bamm /;
my $result = $which_element_is("dino", @names);

sub which_element_is {
my($what, @array) = @_;
foreach(0..$#array){ #indices of @array's elements
if($what eq $array[$_]){
return $_; # return early once found
}
}
-1; #element not found (return is optional here)
}

Omitting the Ampersand
A subroutine call can omit the ampersand. If the compiler sees the subroutine definition before
invocation, or if Perl can tell from the syntax that it is a subroutine call, the subroutine can be called
without an ampersand just like a built-in function.

This means that if Perl can see that it is a subroutine call without the ampersand, from the
syntax alone, that is generally fine. That is, if you have got the parameter list in parentheses, it is got to
be a function call:

my @cards = shuffle(@deck_of_cards); # no & necessary on &shuffle

Or if Perls internal compiler has already seen the subroutine definition, in that case you can even omit
the parentheses around the argument list:
Table 4.14:
sub division {
$_[0] / $_[1]; # divide first param by second
}
my quotient = division 355, 113; #Uses &division
Note:
This works because of the rule that parentheses may always be omitted, except when doing so would
change the meaning of the code.

But do not put the subroutine declaration after the invocation, or the compiler wont know
what the attempted invocation of division is all about. The compiler has to see the definition before the
invocation of the subroutine is all about. The compiler has to see the definition before the invocation in
order to use the subroutine call as if it were a built-in.

If the subroutine has the same name as a Perl built-in, you must use the ampersand to call it.
With an ampersand, you are sure to call the subroutine; without it, you get the subroutine only if there
is no built-in with the same name:



Table 4.15:
sub chomp {
print "Hello SysAd Students!\n";
}

&chomp; # That ampersand is not optional

Nonscalar Return Values
A scalar is not the only kind of return value a subroutine may have. If you call your subroutine in
a list context, it can return a list of values.

Suppose you wanted to get a range of numbers (as from the range operator, ..), except that you
want to be able to count down as well as up. The range operator only counts upward, but that is exactly
fixed:

Table 4.16:
sub list_from_start_to_finish {
if($start < $finish){
#count upwards from start to finish
$start..$finish;
}
else {
#count downwards from finish to start
reverse $finish..$start;
}
}
$start = 11;
$finish = 6;
@c = &list_from_start_to_finish;

The least you can return is nothing at all. A return with no arguments will return undef in a scalar
context or an empty list in a list context. This can be useful for an error return from a subroutine,
signaling to the caller that a more meaningful return value is unavailable.

Persistent, Private Variables
With my we were able to make variables private to a subroutine, although each time we called
the subroutine we had to define them again. With state, we can still have private variables scoped to
the subroutine but Perl will keep their values between calls.

Going back to our first example (Table 4.1), we had a subroutine named myfunc that
incremented a variable. Now that we know about strict, we add that to our program and realize that
our use of the global variable $n is not allowed anymore. We cannot make $n lexical value with my
because it would not retain its value.

Declaring our variable with state tells Perl to retain the variables value between calls to the
subroutine and to make the variable private to the subroutine:

Table 4.16:
use 5.010; # compatible only with Perl version 5.10 and newer

sub myfunc {
state $n = 0; # private, persistent variable $n
$n += 1;
print "hello, student $n!\n";
}

Now we can get the same output while being strict-clean and not using a global variable. The first time
we call the subroutine, Perl declares and initializes $n. Perl ignores the statement on all subsequent
calls. Between calls, Perl retains the value of $n for the next call to the subroutine.

We can make any variable type a state variable; it is not just for scalars. Heres a subroutine that
remembers its arguments and provides a running sum by using a state array:

Table 4.17:
use 5.010;

running_sum(5,6);
running_sum(1..3);
running_sum(4);

sub running_sum {
state $sum = 0;
state @numbers;

foreach my $number(@_){
push @numbers, $number;
$sum += $number;
}
say "The sum of (@numbers) is $sum";
}

Note:
Theres a slight restriction on arrays and hashes as state variables. We cannot initialize then in list
context as of Perl 5.10;

Vous aimerez peut-être aussi