One of the first things I try to learn in an unfamiliar programming language is how it handles closures. Their semantics are often intertwined with how the language handles scopes and various other tricky bits so understanding them reveals several other aspects of the language. Plus, closures are a really powerful construct and often times cut down on the amount of boilerplate I have to type. So I was messing around with perl closures and I stumbled upon a little gotcha:
my @closures;
foreach (1..3) {
# create some closures
push @closures, sub { say "I will remember $_"; };
}
foreach (@closures) {
# call the closures to see what they remember
# the result is not obvious
&{$_}();
}
When I wrote the above code I was expecting to see
I will remember 1
I will remember 2
I will remember 3
but instead I got I will remember CODE(0x986c1f0)
.
The above experiment revealed that $_
is very context dependent and if it appears in a closure then it's value is not fixed at the point of the closure's creation. It behaves more like a reference. What other gotchas should I be aware of when creating closures in perl?
Closure is one of the important concepts in Perl. Closure is a computer term with an accurate but a hard to explain meaning. It is often referred as a function that can be stored as a variable, which has a special ability to access other variables local to the scope it was created in.
Closures are useful because they let you associate data (the lexical environment) with a function that operates on that data. This has obvious parallels to object-oriented programming, where objects allow you to associate data (the object's properties) with one or more methods.
Introduction to JavaScript closures. In JavaScript, a closure is a function that references variables in the outer scope from its inner scope. The closure preserves the outer scope inside its inner scope. To understand the closures, you need to know how the lexical scoping works first.
Closures are a poor man's object." At that moment, Anton became enlightened. The point is that objects and closures are two ways of looking at a thing. In a nutshell, objects are data with behaviour, whereas closures are behaviour with data.
$_ is a global variable and should not be used in closure. Before using it assign this to a lexically scoped variable as shown bewlow. This will produce expected o/p.
#!/usr/bin/perl -w
use strict;
my @closures;
foreach (1..3) {
my $var = $_;
push @closures, sub { print "I will remember $var"; };
}
foreach (@closures) {
$_->();
print "\n";
}
Closures only close over lexical variables; $_
is normally a global variable.
In 5.10 and above, you can say my $_;
to have it be lexical in a given scope (though in 5.18 this was retroactively declared to be experimental and subject to change, so better to use some other variable name).
This produces the output you expected:
use strict;
use warnings;
use 5.010;
my @closures;
foreach my $_ (1..3) {
# create some closures
push @closures, sub { say "I will remember $_"; };
}
foreach (@closures) {
# call the closures to see what they remember
# the result is not obvious
&{$_}();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With