Newbie in Perl again here, trying to understand closure
in Perl.
So here's an example of code which I don't understand:
sub make_saying { my $salute = shift; my $newfunc = sub { my $target = shift; print "$salute, $target!\n"; }; return $newfunc; # Return a closure } $f = make_saying("Howdy"); # Create a closure $g = make_saying("Greetings"); # Create another closure # Time passes... $f->("world"); $g->("earthlings");
So my questions are:
$f = \make_saying("Howdy")
instead? And when can I use the &
because I tried using that in passing the parameters (&$f("world")
) but it doesn't work.world
and earthlings
get appended to the words howdy
and greetings
. Note: I understand that $f is somewhat bound to the function with the parameter howdy
so that's my understanding how the world
got appended. What I don't understand is the 2nd function inside. How that one operates its magic. Sorry I really don't know how to ask this one.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.
To use a closure, define a function inside another function and expose it. To expose a function, return it or pass it to another function. The inner function will have access to the variables in the outer function scope, even after the outer function has returned.
Disadvantages of closures There are two main disadvantages of overusing closures: The variables declared inside a closure are not garbage collected. Too many closures can slow down your application. This is actually caused by duplication of code in the memory.
An autoclosure is a closure that's automatically created to wrap an expression that's being passed as an argument to a function. It doesn't take any arguments, and when it's called, it returns the value of the expression that's wrapped inside of it.
In Perl, scalar variables cannot hold subroutines directly, they can only hold references. This is very much like scalars cannot hold arrays or hashes, only arrayrefs or hashrefs.
The sub { ... }
evaluates to a coderef, so you can directly assign it to a scalar variable. If you want to assign a named function (e.g. foo
), you have to obtain the reference like \&foo
.
You can call coderefs like $code->(@args)
or &$code(@args)
.
The code
$f = \make_saying("Howdy")
evaluates make_saying("Howdy")
, and takes a reference to the returned value. So you get a reference that points to a coderef, not a coderef itself.
Therefore, it can't be called like &$f("world")
, you need to dereference one extra level: &$$f("world")
.
A closure is a function that is bound to a certain environment.
The environment consists of all currently visible variables, so a closure always remembers this scope. In the code
my $x; sub foo { my $y; return sub { "$x, $y" }; }
foo
is a closure over $x
, as the outer environment consists of $x
. The inner sub is a closure over $x
and $y
.
Each time foo
is executed, we get a new $y
and therefore a new closure. Each time it is called, a different closure is returned.
When we execute make_saying("Howdy")
, the $salute
variable is set to Howdy
. The returned closure remembers this scope.
When we execute it again with make_saying("Greetings")
, the body of make_saying
is evaluated again. The $salute
is now set to Greetings
, and the inner sub closes over this variable. This variable is separate from the previous $salute
, which still exists, but isn't accessible except through the first closure.
The two greeters have closed over separate $salute
variables. When they are executed, their respective $salute
is still in scope, and they can access and modify the value.
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