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 {
Every time you call the subroutine 'make_saying', it:
creates a DIFFERENT closure
assigns the received parameter to the scalar '$salute'
defines (creates but not execute) an inner anonymous subroutine:
That is the reason why at that moment nothing is assigned to the scalar
$target
nor is the statement print "$salute, $target!\n";
executed .
finally the subroutine 'make_saying' returns a reference to the inner anonymous subroutine, that reference becomes the only way to call the (specific) anonymous subroutine.
Ever time you call each anonymous subroutine, it:
assign the received parameter to the scalar $target
sees also the scalar $salute
that will have the value assigned at the moment in which was created the anonymous subroutine (when was called its parent subroutine make_saying
finally executes the statement print "$salute, $target!\n";
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 a variable is asigned to a function, is it automatically a reference to that function?
No. In example the function make_saying
return reference another function. Such closures do not have name and can catch a variable from outside its scope (variable $salute
in your example).
In that above code, can i write $f = \make_saying("Howdy") instead? And when can i use the & cause i tried using that in passing the parameters (&$f("world")) but it doesnt work.
No. $f = \make_saying("Howdy")
is not what you think (read amon post for details). You can write $f = \&make_saying;
which means "put into $f reference to function make_saying". You can use it later like this:
my $f = \&make_saying;
my $other_f = $f->("Howdy");
$other_f->("world");
and lastly, In that code above how in he** did the words world and earthlings got appended to the words howdy and greetings.
make_saying creating my variable which goes into lamda (my $newfunc = sub
); that lambda is returned from make_saying. It holds the given word "Howdy" through "closing" (? sorry dont know which word in english).