Yes it is a closure. There is some ambiguity in the perl world about the word closure. For various reasons there isa tradition of using the word "closure" as a synonym for "anonymous sub". However the basic fact is that your subroutine addone() is a closure around the $i in the block. Try using Data::Dump::Streamer on \&addone and note that the $i will be dumped. DDS uses the internal structure of the subroutine to do its thing so this is a definitive check. If DDS doesnt dump any vars external to the subroutine then the subroutine is not a closure. If it does then it is a closure.

Where the problem arises is that the type of closure you have in the example is so trivial that it can be just as easily explained in terms of a non-closure based behaviour, that of static storage. However a close inspection will show that the code does not behave as you might expect if it really was using static code. Consider what happens if we have a call to the sub prior to the initialization of the var it binds to. Something like the following:

use Data::Dump::Streamer; my $x=counter(); { my $i=1; sub counter { my $r=$i; $i++; $r }; } Dump($x,\&counter)->Names(qw(x *counter))->Out(); __END__ my ($i); $i = 1; $x = undef; sub counter { my $r = $i; ++$i; $r; };

As you can see the value of $x is undefined. This is because named subroutines are compiled and bound to the vars they enclose at compile time. But any initialization happens at run time. If you wrapped this code in a loop you would not get a new var every time. Compare that to this:

use Data::Dump::Streamer; { sub make_counter { my $i=shift; return sub { my $r=$i; $i++; $r } +}; } my @counters=map { make_counter($_) } 1..5; Dump(\@counters); __END__ my ($i,$i_eclipse_1,$i_eclipse_2,$i_eclipse_3,$i_eclipse_4); $i = 1; $i_eclipse_1 = 2; $i_eclipse_2 = 3; $i_eclipse_3 = 4; $i_eclipse_4 = 5; $ARRAY1 = [ sub { my $r = $i; ++$i; $r; }, sub { my $r = $i_eclipse_1; ++$i_eclipse_1; $r; }, sub { my $r = $i_eclipse_2; ++$i_eclipse_2; $r; }, sub { my $r = $i_eclipse_3; ++$i_eclipse_3; $r; }, sub { my $r = $i_eclipse_4; ++$i_eclipse_4; $r; } ];

As you can see each subroutine gets bound to a different $i (renamed by DDS to $i_ecplise_N because the various $i's are "eclipsed" by each other and DDS isn't smart enough to figure out the scoping required to de-ecplipse them). This behaviour occurs only with anonymous closures for arcane reasons in the perl internals. But its this behaviour that makes closures really interesting, so the confusion is not that hard to understand.

Anyway, a "closure" is just a subroutine that is "bound to" or "encloses" vars declared external to itself. Its a special type of reference containment that does not occur by membership of a composite but because of its use in the code of the subroutine. So if a subroutine does not refer to lexical variables that were declared outside of its body it is not a closure. If a subroutine does refer to lexical variables that were declared outside of its body then it is a closure. Note that this is strictly lexicals, its not globals (use vars qw(); or our($vars)) as globals are like symlinks, they refer to a name of variable and not the variable itself. Thus a subroutine does not bind to globals it binds to the globals name, which isnt the same thing as with lexicals where the compiler doesn't actually care what the called once the compile phase is complete, in fact the var names are only tracked for convenience (such as debugging).

I bet this was far more than you wanted to know but I hope its been more englightening than confusing.

---
$world=~s/war/peace/g


In reply to Re: Nailing down closures! by demerphq
in thread Nailing down closures! by mattford63

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.