Skip to content

Latest commit

 

History

History
304 lines (204 loc) · 8.14 KB

anonymous_functions.pod

File metadata and controls

304 lines (204 loc) · 8.14 KB

Anonymous Functions

An anonymous function is a function without a name. It behaves like a named function--you can invoke it, pass arguments to it, return values from it, copy references to it--it can do anything a named function can do. The difference is that it has no name. You always deal with anonymous functions by reference (see references and function_references).

Declaring Anonymous Functions

You may never declare an anonymous function on its own; you must construct it and assign it to a variable, invoke it immediately, or pass it as an argument to a function, either explicitly or implicitly. Explicit creation uses the sub keyword with no name:

A common Perl 5 idiom known as a dispatch table uses hashes to associate input with behavior:

The dispatch() function takes arguments of the form (2, 'times', 2) and returns the result of evaluating the operation.

You may use anonymous functions in place of function references. To Perl, they're equivalent. Nothing necessitates the use of anonymous functions to perform these mathematical operations, but for functions this short, there's little drawback to writing them this way.

You may rewrite %dispatch as:

... but the decision to do so depends more on maintainability concerns, safety, and your team's coding style than any language feature.

You may also create anonymous functions on the spot when passing them as function parameters:

Anonymous Function Names

There is one instance in which you can identify the difference between a reference to a named function and an anonymous function--anonymous functions do not (normally) have names. This may sound subtle and silly and obvious, but introspection shows the difference:

The result may be surprising:

Called from ShowCaller::B<main> in ShowCaller at anoncaller.pl : 20
Called from ShowCaller::B<__ANON__> in ShowCaller at anoncaller.pl : 17

The __ANON__ in the second line of output demonstrates that the anonymous function has no name that Perl can identify. Even though this can be difficult to debug, there are ways around this anonymity.

The CPAN module Sub::Identify provides a handful of functions useful to inspect the names of functions, given references to them. sub_name() is the most immediately obvious:

As you might imagine, the lack of identifying information complicates debugging anonymous functions. The CPAN module Sub::Name can help. Its subname() function allows you to attach names to anonymous functions:

This program produces:

__ANON__
pseudo-anonymous
pseudo-anonymous
__ANON__

Note that both references refer to the same underlying anonymous function. Calling subname() on $anon and returning into $named modifies that function, so any other reference to this function will see the same moniker.

Implicit Anonymous Functions

All of these anonymous function declarations have been explicit. Perl 5 allows implicit anonymous functions through the use of prototypes (prototypes). Though this feature exists nominally to enable programmers to write their own syntax such as that for map and eval, an interesting example is the use of delayed functions that don't look like functions. Consider the CPAN module Test::Exception:

Both lives_ok() and throws_ok() take an anonymous function as their first arguments. This code is equivalent to:

... but is slightly easier to read.

The implementation of both functions does not care which mechanism you use to pass function references. You can pass named functions by reference as well:

... but you may not pass them as scalar references:

... because the prototype changes the way the Perl 5 parser interprets this code. It cannot determine with 100% clarity what $croak and $add will contain when it evaluates the throws_ok() or lives_ok() calls, so it produces an error:

This feature is occasionally useful despite its drawbacks. The syntactic clarity available by promoting bare blocks to anonymous functions can be helpful, but use it sparingly and document the API with care.

POD ERRORS

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

Around line 3:

A non-empty Z<>