What is meant by proper closure here
Asked Answered
F

3

6

This is a code lifted straight from Perl Cookbook:

@colors = qw(red blue green yellow orange purple violet);
for my $name (@colors) {
no strict 'refs';
*$name = sub { "<FONT COLOR='$name'>@_</FONT>" };
}

It's intention is to form 6 different subroutines with names of different colors. In the explanation part, the book reads:

These functions all seem independent, but the real code was in fact only compiled once. This technique saves on both compile time and memory use. To create a proper closure, any variables in the anonymous subroutine must be lexicals. That's the reason for the my on the loop iteration variable.

What is meant by proper closure, and what will happen if the my is omitted? Plus how come a typeglob is working with a lexical variable, even though typeglobs cannot be defined for lexical variables and should throw error?

Fumed answered 21/8, 2012 at 15:16 Comment(0)
M
7

As others have mentioned the cookbook is using the term "proper" to refer to the fact that a subroutine is created that carries with it a variable that is from a higher lexical scope and that this variable can no longer be reached by any other means. I use the over simplified mnemonic "Access to the $color variable is 'closed'" to remember this part of closures.

The statement "typeglobs cannot be defined for lexical variables" misunderstands a few key points about typeglobs. It is somewhat true it you read it as "you cannot use 'my' to create a typeglob". Consider the following:

my *red = sub { 'this is red' };

This will die with "syntax error near "my *red" because its trying to define a typeglob using the "my" keyword.

However, the code from your example is not trying to do this. It is defining a typeglob which is global unless overridden. It is using the value of a lexical variable to define the name of the typeglob.

Incidentally a typeglob can be lexically local. Consider the following:

my $color = 'red';

# create sub with the name "main::$color". Specifically "main:red"
*$color = sub { $color };

# preserve the sub we just created by storing a hard reference to it.
my $global_sub = \&$color;

{
  # create a lexically local sub with the name "main::$color".
  # this overrides "main::red" until this block ends
  local *$color = sub { "local $color" };

  # use our local version via a symbolic reference.
  # perl uses the value of the variable to find a
  # subroutine by name ("red") and executes it
  print &$color(), "\n";

  # use the global version in this scope via hard reference.
  # perl executes the value of the variable which is a CODE
  # reference.
  print &$global_sub(), "\n";

  # at the end of this block "main::red" goes back to being what
  # it was before we overrode it.
}

# use the global version by symbolic reference
print &$color(), "\n";

This is legal and the output will be

local red
red
red

Under warnings this will complain "Subroutine main::red redefined"

Monolithic answered 21/8, 2012 at 16:9 Comment(2)
Thanks. Can you explain why does the 2nd print &$global_sub() within the block print out red, even though $global_sub holds a reference to a sub with name red and this sub has just been redefined locally within the block?Fumed
@Cupidvogel $global_sub holds a CODE reference. This is a reference to the compiled code and not to the subroutine name. It was created by referencing a subroutine by name but once the reference is stored the reference it is no longer defined by that name. The line where it is used doesn't call it by name, it calls it using the reference to the code itself. I added clarifications where symbolic (by name) and hard (CODE) references are being used. Hopefully that helps.Monolithic
B
6

I believe that "proper closure" just means actually a closure. If $name is not a lexical, all the subs will refer to the same variable (whose value will have been reset to whatever value it had before the for loop, if any).

*$name is using the value of $name as the reference for the funny kind of dereferencing a * sigil does. Since $name is a string, it is a symbolic reference (hence the no strict 'refs').

Barmen answered 21/8, 2012 at 15:56 Comment(0)
R
1

From perlfaq7:

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.

The answer carries on to answer the question in some considerable detail.

The Perl FAQs are a great resource. But it's a bit of a waste of effort maintaining them if no-one ever reads them.

Edit (to better answer the later questions in your post):

1/ What is meant by proper closure? - see above

2/ What will happen if the my is omitted? - It won't work. Try it and see what happens.

3/ How come a typeglob is working with a lexical variable? - The variable $name is only being used to define the name of the typeglob to work with. It's not actually being used as a typeglob.

Does that help more?

Rainproof answered 21/8, 2012 at 15:28 Comment(1)
That was helpful, but not the answer I am looking for.Fumed

© 2022 - 2024 — McMap. All rights reserved.