Advanced Perl Programming

Advanced Perl ProgrammingSearch this book
Previous: 3.4 Filehandles, Directory Handles, and Formats Chapter 4 Next: 4.2 Using Subroutine References
 

4. Subroutine References and Closures

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.

4.1 Subroutine References

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.

4.1.1 References to Named Subroutines

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.

4.1.2 References to Anonymous Subroutines

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.

4.1.3 Dereferencing Subroutine References

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";
}

4.1.4 Symbolic References

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.


Previous: 3.4 Filehandles, Directory Handles, and Formats Advanced Perl Programming Next: 4.2 Using Subroutine References
3.4 Filehandles, Directory Handles, and Formats Book Index 4.2 Using Subroutine References