How do closures in Perl work?

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).

Tags:

Perl

Closures