One of the things when I get an unexpected closure binding is to print both the reference to the variables I'm expecting to be bound, and the resulting coderef. By watching the addresses change (or not) I can tell whether the variables have independant binding (or not). For example:
for ($i = 1; $i <= 8; $i++) { print "\\\$i is ", \$i, "\n"; my $c = sub { print "\$i is $i\n" }; print "\$c is $c\n"; push @codes, $c; }
For this one, I got:
\$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04) \$i is SCALAR(0x80ce98c) $c is CODE(0x80cea04)
showing that we are neither looking at distinct $i nor a closure (the addresses are all identical). Now, let's add a my declaration:
for (my $i = 1; $i <= 8; $i++) { print "\\\$i is ", \$i, "\n"; my $c = sub { print "\$i is $i\n" }; print "\$c is $c\n"; push @codes, $c; }
and notice that we now get a closure (the coderef addresses change):
\$i is SCALAR(0x80ce974) $c is CODE(0x80c83ac) \$i is SCALAR(0x80ce974) $c is CODE(0x80d22f8) \$i is SCALAR(0x80ce974) $c is CODE(0x80d2364) \$i is SCALAR(0x80ce974) $c is CODE(0x80d23d0) \$i is SCALAR(0x80ce974) $c is CODE(0x80d243c) \$i is SCALAR(0x80ce974) $c is CODE(0x80d24a8) \$i is SCALAR(0x80ce974) $c is CODE(0x80d2514) \$i is SCALAR(0x80ce974) $c is CODE(0x80d2580)
So, even though these are all closures, they are all linked to the same now changed $i. This will protect them for when the $i goes out of scope, but they still all share the same one. What we need is to have a "different" $i each time:
foreach my $i (1..8) { print "\\\$i is ", \$i, "\n"; my $c = sub { print "\$i is $i\n" }; print "\$c is $c\n"; push @codes, $c; }
Ahh, there we go, now we got it:
\$i is SCALAR(0x80c83ac) $c is CODE(0x80ce95c) \$i is SCALAR(0x80d21b8) $c is CODE(0x80d21c4) \$i is SCALAR(0x80d2230) $c is CODE(0x80d223c) \$i is SCALAR(0x80d22a8) $c is CODE(0x80d22b4) \$i is SCALAR(0x80d2320) $c is CODE(0x80d232c) \$i is SCALAR(0x80d2398) $c is CODE(0x80d23a4) \$i is SCALAR(0x80d2410) $c is CODE(0x80d241c) \$i is SCALAR(0x80d2488) $c is CODE(0x80d2494)
See the distinct $i variables, as well as the closures created for them!

Hopefully, this kind of reference-to examination will give you more clues faster when you can't see why things are shared or not. Very helpful for those $x won't stay shared diagnostics.

-- Randal L. Schwartz, Perl hacker


In reply to Closures (was Re: for loops) by merlyn
in thread for loops, closures by Aighearach

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.