Arguments and Return Values in Perl

In this third part of a six-part article series on subroutines and functions in Perl, you’ll learn about passing arguments into functions, and implicitly and explicitly getting return values. This article was excerpted from chapter six of the book Beginning Perl, Second Edition, written by James Lee (Apress; ISBN: 159059391X).

Passing Arguments into Functions

As well as being set pieces of code to be executed whenever we need them, we can also use our user-defined functions just like Perl’s built-in functions—we can pass arguments (aka parameters) to the subroutine and expect an answer back.

Just like with Perl’s built-ins, we pass parameters by placing them between the parentheses:

my_sub(10,15);

What happens to them there? Well, they end up in one of Perl’s special variables, the array @_ , and from there we can get at them. We’ll illustrate this with a subroutine that takes a list of values, adds them up, and prints the total. This example, total1.pl , contains a function named total() that loops through the argument list @_ and sums the arguments passed in:

#!/usr/bin/perl -w
# total1.pl

use strict;

total(111, 107, 105, 114, 69);
total(1…100);
sub total {
my $total = 0;
$total += $_ foreach @_;
print "The total is $totaln";
}

And to see it in action:

$ perl total1.pl
The total is 506
The total is 5050
$

This program illustrates that we can pass any list to a subroutine, just like we can to print() . When we do so, the list ends up in @_ , where it’s up to us to do something with it. Here, we go through each element of it and add them up:

$total += $_ foreach @_;

This is a little cryptic, but it’s how you’re likely to see it done if written by an experienced Perl programmer. You could write this a little less tersely as follows:

my @args = @_ ;
foreach my $element (@args) {
$total = $total + $element;
}

In the first example, @_ would contain (111, 107, 105, 114, 69) , and we’d add each value to $total in turn.

{mospagebreak title=Return Values}

Sometimes we don’t want to perform an action like printing out the total, but instead we want to return the total. We may also want to return a result to indicate whether what we were doing succeeded. This will allow us to say things like

$sum_of_100 = total(1..100);

There are two ways to do this: implicitly or explicitly. The implicit way is nice and easy—we just make the value we want to return the last thing in our subroutine:

#!/usr/bin/perl -w
# total2.pl

use strict;

my $total = total(111, 107, 105, 114, 69);
print "the total is: $totaln";
my $sum_of_100 = total(1..100);
print "the sum of 100 is: $sum_of_100n";

sub total {
my $total = 0;
$total += $_ foreach @_;
$total;
}

Running this code results in the following:

$ perl total2.pl
the total is: 506
the sum of 100 is: 5050
$

The last expression in the function doesn’t need to be a variable: we could use any expres sion. We can also return a list instead of a single scalar.

Here is an example of returning a list from a function. Let’s convert a number of seconds to hours, minutes, and seconds. We pass the time in seconds into the subroutine, and it returns a three-element list with the hours, minutes, and remaining seconds.

#!/usr/bin/perl – w
# seconds.pl

use strict;

my ($hours, $minutes, $seconds) = secs2hms(3723);
print "3723 seconds is $hours hours, $minutes minutes and $seconds seconds"; print "n";

sub secs2hms {
my ($h,$m);
my $seconds = shift; # defaults to shifting @_
$h = int($seconds/(60*60));
$seconds %= 60*60;
$m = int($seconds/60);
$seconds %= 60;
($h,$m,$seconds);
}

This tells us that

$ perl seconds.pl
3723 seconds is 1 hours, 2 minutes and 3 seconds
$

This program illustrates that just like a built-in function, when we’re expecting a subroutine to return a list, we can use an array or list of variables to collect the return values:

my ($hours, $minutes, $seconds) = secs2hms(3723);

When secs2hms() returns, this will be equivalent to

my ($hours, $minutes, $seconds) = (1,2,3);

And now let’s look at how the subroutine works. We start in the usual way: sub , the name, and a block.

sub secs2hms {

We have two variables to represent hours and minutes, and we read the parameters in from @_ –if you don’t tell shift() which array to take data from, it’ll read from @_ if you’re in a subroutine or @ARGV if you’re not. Therefore, the first argument to secs2hms() , 3723, is shifted into $seconds :

my ($h,$m);
my $seconds = shift;

Then the actual conversion: there are 3600 (60*60) seconds in an hour, and so the number of hours is the number of seconds divided by 3600. However, that’ll give us a floating point number—if we divided 3660 by 3600, we’d get 1.0341666. We’d rather have “one and a bit,” so we use int() to get the integer value, the “1” part of the division, and use the modulus oper ator to get the remainder; having dealt with the first 3600 seconds, we want to carry on looking at the next 123.

$h = int($seconds/(60*60));
$seconds %= 60*60;

The second statement sets $seconds to $seconds % (60*60) —if it was 3723 before, it’ll be 123 now.

The same goes for minutes: we divide to get “two and a bit,” and getting the remainder tells us that there are 3 seconds outstanding. Hence, our values are 1 hour, 2 minutes, and 3 seconds.

$m = int($seconds/60);
$seconds %= 60;

We return this just by leaving a list of the values as the last thing in the subroutine.

($h,$m,$seconds);

The return Statement

The explicit method of returning something from a subroutine is to say return(…) . The first return statement we come across will immediately return to the caller. For example:

sub secs2hms {
my ($h,$m);
my $seconds = shift;
$h = int($seconds/(60*60));
$seconds %= 60*60;
$m = int($seconds/60);
$seconds %= 60;
 
return ($h,$m,$seconds);
print "This statement is never reached.";

}

This also means we can have more than one return statement, and it’s often useful to do so.

Please check back for the next part of this series.

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort