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.
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 :
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.
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:
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:
Some sample usage:
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? |