Professional Perl | 13 | WebReference

Professional Perl | 13

To page 1To page 2current pageTo page 4
[previous] [next]

Professional Perl

Converting Scalar Subroutines into List Processors

Consider this subroutine, which capitalizes the first letter of the string that it is passed:

sub capitalize {
   $_[0] = ucfirst(lc $_[0]);
   print "$_[0]";
}
$country = "england";
capitalize($country);   # produces 'England'

Simple enough, but it only works on one string at a time. However, just because we wrote this subroutine to work as a scalar operator does not alter the fact that in reality it is working on a list. We have just limited it to handle a list with one value. With only a little extra effort we can turn this subroutine into something that works on scalars and lists alike:

sub capitalize {
   foreach (@_) {
      $_ = ucfirst lc;   # lc uses $_ if argument is omitted
      print "$_[0]";
   }
}

Or more efficiently, with map:

sub capitalize {
   map {$_ = ucfirst lc} @_;
   print "$_[0]";
}

This version works identically for calls like the above that pass only one parameter, but also happily works on arrays too:

sub capitalize {
   map {$_ = ucfirst lc} @_;
   print "@_[0, 1, 2]";
}
@countries = ("england", "scotland", "wales");
capitalize (@countries);   # produces ("England", "Scotland", "Wales")

Passing '@_' Directly into Subroutines

We said earlier that the @_ array is distinct to each subroutine and masks any previous definition. That is almost true - there is one exception provided, for reasons of efficiency, to the Perl programmers dedicated to optimizing their code. Normally @_ is defined locally, on entry to each subroutine. So, if we pass in no parameters at all we get an empty array. However, if we call a subroutine using the & prefix and do not pass parameters or use braces then the subroutine inherits the @_ array of the calling subroutine directly:

&mysubroutine;   # inherit @_ from parent	

The problem with this technique is that it is rather arcane, and not obvious to the reader of our code. Therefore, if we use it, a comment to the effect that this is what we are doing (such as the one above) is highly recommended.

As far as the subroutine is concerned this is no different to passing the @_ array as a parameter:

mysubroutine(@_);

Although, this may seem equivalent, in the second case the @_ array is copied each time the call is made. If @_ contains a large number of values, or many calls are made (for instance in a recursive subroutine) then this is potentially expensive. The &mysubroutine; notation passes the @_ array directly, without making a copy, and so avoids the unnecessary work. Whether this is worth the trouble or not is of course another matter. If @_ only contains a few elements, it is probably better to live with the very minor inefficiency of copying the array and use the explicit version.

Note that the aliasing of the values in the @_ array to the original variables (if the parameter was a variable) happens in either case, so it is not necessary to resort to this practice if all we want to do is modify the variables that were passed to us.

To page 1To page 2current pageTo page 4
[previous] [next]

and
Revised: March 22, 2001
Created: March 22, 2001

URL: https://webreference.com/programming/perl/professional/chap7/3/