FAQ 7.13 What's a closure?

P

PerlFAQ Server

This is an excerpt from the latest version perlfaq7.pod, which
comes with the standard Perl distribution. These postings aim to
reduce the number of repeated questions as well as allow the community
to review and update the answers. The latest version of the complete
perlfaq is at http://faq.perl.org .

--------------------------------------------------------------------

7.13: What's a closure?

Closures are documented in perlref.

*Closure* is a computer science term with a precise but hard-to-explain
meaning. Usually, closures are implemented in Perl as anonymous
subroutines with lasting references to lexical variables outside their
own scopes. These lexicals magically refer to the variables that were
around when the subroutine was defined (deep binding).

Closures are most often used in programming languages where you can have
the return value of a function be itself a function, as you can in Perl.
Note that some languages provide anonymous functions but are not capable
of providing proper closures: the Python language, for example. For more
information on closures, check out any textbook on functional
programming. Scheme is a language that not only supports but encourages
closures.

Here's a classic non-closure function-generating function:

sub add_function_generator {
return sub { shift() + shift() };
}

$add_sub = add_function_generator();
$sum = $add_sub->(4,5); # $sum is 9 now.

The anonymous subroutine returned by add_function_generator() isn't
technically a closure because it refers to no lexicals outside its own
scope. Using a closure gives you a *function template* with some
customization slots left out to be filled later.

Contrast this with the following make_adder() function, in which the
returned anonymous function contains a reference to a lexical variable
outside the scope of that function itself. Such a reference requires
that Perl return a proper closure, thus locking in for all time the
value that the lexical had when the function was created.

sub make_adder {
my $addpiece = shift;
return sub { shift() + $addpiece };
}

$f1 = make_adder(20);
$f2 = make_adder(555);

Now "&$f1($n)" is always 20 plus whatever $n you pass in, whereas
"&$f2($n)" is always 555 plus whatever $n you pass in. The $addpiece in
the closure sticks around.

Closures are often used for less esoteric purposes. For example, when
you want to pass in a bit of code into a function:

my $line;
timeout( 30, sub { $line = <STDIN> } );

If the code to execute had been passed in as a string, '$line =
<STDIN>', there would have been no way for the hypothetical timeout()
function to access the lexical variable $line back in its caller's
scope.

Another use for a closure is to make a variable *private* to a named
subroutine, e.g. a counter that gets initialized at creation time of the
sub and can only be modified from within the sub. This is sometimes used
with a BEGIN block in package files to make sure a variable doesn't get
meddled with during the lifetime of the package:

BEGIN {
my $id = 0;
sub next_id { ++$id }
}

This is discussed in more detail in perlsub, see the entry on
*Persistent Private Variables*.



--------------------------------------------------------------------

The perlfaq-workers, a group of volunteers, maintain the perlfaq. They
are not necessarily experts in every domain where Perl might show up,
so please include as much information as possible and relevant in any
corrections. The perlfaq-workers also don't have access to every
operating system or platform, so please include relevant details for
corrections to examples that do not work on particular platforms.
Working code is greatly appreciated.

If you'd like to help maintain the perlfaq, see the details in
perlfaq.pod.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top