Contents:
Subroutine References
Using Subroutine References
Closures
Using Closures
Comparisons to Other Languages
Resources
Many are called, but few are called back.
- Sister Mary Tricky
As with ordinary variables, subroutines can be named or anonymous, and Perl has a syntax for taking a reference to either type. Such references work rather like pointers to functions in C, and they can be used to create such sophisticated structures as the following:
Dispatch tables. Or data structures that map events to subroutine references. When an event comes in, a dispatch table is used to look up the corresponding subroutine. This is useful in creating large and efficient switch statements, finite state machines, signal handlers, and GUI toolkits.
Higher-order procedures. A higher-order procedure takes other procedures as arguments (like the C library procedure qsort) or returns new procedures. The latter feature is available only in interpreted languages such as Perl, Python, and LISP (hey, LISPers, you have lambda functions!).
Closures. A closure is a subroutine that, when created, packages its containing subroutine's environment (all the variables it requires and that are not local to itself).
In the following sections, we look at the syntax for taking and managing subroutine references and subsequently use them in the applications listed.
There's nothing particularly fancy or magical about subroutine references. In this section, we'll study how to create references to named and anonymous subroutines and how to dereference them.
We saw earlier that to take a reference to an existing variable, we prefix it with a backslash. It is much the same with subroutines. \&mysub is a reference to &mysub. For example:
sub greet { print "hello \n"; } $rs = \&greet; # Create a reference to subroutine greet
It is important to note that we are not calling the greet subroutine here, in the same way that we don't evaluate the value of a scalar when we take a reference to it.
Contrast this to the following code, which uses parentheses:
$rs = \&greet();
This expression likely doesn't do what you expect. It calls greet and produces a reference to its return value, which is the value of the last expression evaluated inside that subroutine. Since print executed last and returned a 1 or a 0 (indicating whether or not it was successful in printing the value), the result of this expression is a reference to a scalar containing 1 or 0! These are the kind of mistakes that make you wish for type-safety once in a while!
To summarize, do not use parentheses when taking a subroutine reference.
You can create an anonymous subroutine simply by omitting the name in a subroutine declaration. In every other respect, the declaration is identical to a named one.
$rs = sub { print "hello \n"; };
This expression returns a reference to the newly declared subroutine. Notice that because it is an expression, it requires the semicolon at the end, unlike the declaration of a named subroutine.
Dereferencing a subroutine reference calls the subroutine indirectly. As with data references, Perl does not care whether $rs is pointing to a named or an anonymous subroutine; dereferencing works the same way in either case.
It should come as no surprise that prepending $rs with the appropriate prefix - "&", in this case - dereferences it:
&$rs(10, 20); # Call the subroutine indirectly
That's all there is to it.
Just as you can use the -> syntax with arrays or hashes ($ra->[10] or $rh->{'k2'}), you can call subroutines indirectly through references, like this:
$rsub->(10);
In fact, subroutine calls can be chained if the intermediate calls return subroutine references. For example:
$rs = \&test1; $rs->("Batman")->("Robin"); # Prints "Batman and Robin" sub test1 { my $arg = shift; print "$arg"; return \&test2; } sub test2 { my $arg = shift; print " and $arg\n"; }
Recall that symbolic references contain names (strings), not real references. There is no difference in syntax between real and symbolic references. Consider
sub foo { print "foo called\n" } $rs = "foo"; &$rs(); # prints "foo called"
Using symbolic references is a mite slower than using real references.