Item 28: Use prototypes to get special argument parsing.


Item 28: Use prototypes to get special argument parsing.

Perl has supported subroutine prototypes for some time. Perl prototypes are not named, typed formal parameters along the lines of those in ISO C, [8] but are rather a mechanism that allows programmers to write subroutines whose arguments are treated like those of built-in operators.

[8] Not yet, anyway.

As an example, consider implementing a pop2 function that removes and returns two elements from the end of an array. Suppose you want to be able to use it like the built-in pop :

 @a = 1..10;  $item = pop @a;  ($item1, $item2) = pop2_ref \@a; 

Here's how we pop .

How we'd like to pop2 .

Normally, if you wanted to implement something like pop2 , you would use references (see Item 26):

 sub pop2_ref { splice @{$_[0]}, -2, 2 } 

But this has to be called with a reference to an array, not the name of the array:

 @a = 1..10;  ($item1, $item2) = pop2 @a; 

You have to use prototypes in order to write a function that gets the special treatment of its argument list that a built-in operator like pop does. A prototype appears at the beginning of a subroutine declaration or definition:

 sub pop2 (\@) { splice @{$_[0]}, -2, 2 } 

Prototypes are made up of prototype atoms. Prototype atoms are characters , possibly preceded by a backslash, indicating the type of argument(s) to be accepted by a subroutine. In this example, the \@ atom indicates that the subroutine pop2 is to take a single named array argument. A backslashed atom, like \$ or \@ , causes Perl to pass a reference to the corresponding argument, so in this case the array argument to pop2 will be passed as a reference, not as a list of values.

Prototype atoms

Kind

Syntax

Description

Name

\$ , \@ , \% , \& , \*

Returns reference to variable name or argument beginning with $ , @ , % , etc.

Scalar

$

Forces scalar context.

List

@ , %

Gobbles the rest of the arguments; forces list context.

Block

&

Code ref; sub keyword optional if first argument.

Glob

*

Create a typeglob ref.

Optional

;

Separate required args from optional args.

Prototypes also invoke argument type and number checking where appropriate. For example, if you try to invoke pop2 on a non-array value:

 pop2 %hash 

the result is a compile-time error:

 Type of arg 1 to main::pop2 must be array (not associative  array deref) 

Let's look at a couple of examples. First, how about a subroutine that takes two array arguments and "blends" them into a single listone element from the first array, then one from the second, then another from the first, and so on:

 sub blend (\@\@) {    local (*a, *b) = @_;    my $n = $#a > $#b ? $#a : $#b;    my @res; 

Faster than lots of derefs.

 for my $i (0..$n) {      push @res, $a[$i], $b[$i];    }    @res;  } 

Could have been map { $a[$_], $b[$_] } 0..$n, but for and push are faster.

Here's how you would use it:

 blend @a, @b;  blend @{[1..10]}, @{[11..20]}; 

Along the same lines, how about a subroutine that will iterate through the elements of a list like foreach , but n at a time:

 sub for_n (&$@) {    my ($sub, $n, @list) = @_;    my $i;    while ($i <= $#list) {      &$sub(@list[$i .. ($i + $n - 1)]);      $i += $n;    }  } 

First argument is a code ref (anonymous subroutine).

Pass $n elements at a time to the subroutine.

Some sample usage:

 @a = 1..10;  for_n { print "$_[0], $_[1]\n" } 2, @a; 

Loop through @a , two elements at a time.

Prototypes are intended mostly for the use of module writers, but you may find ordinary uses for them as well. For example, prototypes make an excellent parameter-checking mechanism for functions that take a fixed number of scalar arguments.

You should be careful when using atoms like \@ and \% in code that you are going to share with the world, because other programmers may not expect subroutines to take arguments by reference without an explicit backslash. But this shouldn't be a problem, since you always document your code, right?



Effective Perl Programming. Writing Better Programs with Perl
Effective Perl Programming: Writing Better Programs with Perl
ISBN: 0201419750
EAN: 2147483647
Year: 1996
Pages: 116

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net