Skip to content

Latest commit

 

History

History
247 lines (167 loc) · 6.97 KB

prototypes.pod

File metadata and controls

247 lines (167 loc) · 6.97 KB

Prototypes

A prototype is a piece of optional metadata attached to a function which changes the way the parser understands its arguments. While they may superficially resemble function signatures in other languages, they are very different.

Prototypes allow users to define their own functions which behave like builtins. Consider the builtin push, which takes an array and a list. While Perl 5 would normally flatten the array and list into a single list passed to push, the parser knows not to flatten the array so that push can modify it in place.

Function prototypes are part of declarations:

Any prototype attached to a forward declaration must match the prototype attached to the function declaration. Perl will give a warning if this is not true. Strangely you may omit the prototype from a forward declaration and include it for the full declaration--but there's no reason to do so.

The builtin prototype takes the name of a function and returns a string representing its prototype. Use the CORE:: form to see the prototype of a builtin:

prototype will return undef for those builtins whose functions you cannot emulate:

Remember push?

The @ character represents a list. The backslash forces the use of a reference to the corresponding argument. This prototype means that push takes a reference to an array and a list of values. You might write mypush as:

Other prototype characters include $ to force a scalar argument, % to mark a hash (most often used as a reference), and & to identify a code block. See perldoc perlsub for full documentation.

The Problem with Prototypes

Prototypes change how Perl parses your code and can cause argument type coercions. They do not document the number or types of arguments functions expect, nor do they map arguments to named parameters.

Prototype coercions work in subtle ways, such as enforcing scalar context on incoming arguments:

... but only work on simple expressions:

To debug this, users of mypush must know both that a prototype exists, and the limitations of the array prototype. Worse yet, these are the simple errors prototypes can cause.

Good Uses of Prototypes

Few uses of prototypes are compelling enough to overcome their drawbacks, but they exist.

First, they can allow you to override builtins. First check that you can override the builtin by examining its prototype in a small test program. Then use the subs pragma to tell Perl that you plan to override a builtin, and finally declare your override with the correct prototype:

Beware that the subs pragma is in effect for the remainder of the file, regardless of any lexical scoping.

The second reason to use prototypes is to define compile-time constants. When Perl encounters a function declared with an empty prototype (as opposed to no prototype) and this function evaluates to a single constant expression, the optimizer will turn all calls to that function into constants instead of function calls:

All subsequent code will use the calculated value of pi in place of the bareword PI or a call to PI(), with respect to scoping and visibility.

The core pragma constant handles these details for you. The Const::Fast module from the CPAN creates constant scalars which you can interpolate into strings.

A reasonable use of prototypes is to extend Perl's syntax to operate on anonymous functions as blocks. The CPAN module Test::Exception uses this to good effect to provide a nice API with delayed computationSee also Test::Fatal. Its throws_ok() function takes three arguments: a block of code to run, a regular expression to match against the string of the exception, and an optional description of the test:

The exported throws_ok() function has a prototype of &$;$. Its first argument is a block, which becomes an anonymous function. The second argument is a scalar. The third argument is optional.

Careful readers may have spotted the absence of a comma after the block. This is a quirk of the Perl 5 parser, which expects whitespace after a prototyped block, not the comma operator. This is a drawback of the prototype syntax.

You may use throws_ok() without taking advantage of the prototype:

A final good use of prototypes is when defining a custom named function to use with sortBen Tilly suggested this example.:

The prototype of $$ forces Perl to pass the sort pairs in @_. sort's documentation suggests that this is slightly slower than using the package globals $a and $b, but using lexical variables often makes up for any speed penalty.

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 3:

A non-empty Z<>

Around line 186:

Deleting unknown formatting code N<>

Around line 229:

Deleting unknown formatting code N<>