This is a perfectly good example of a closure -- by the book, one might almost say.

(Indeed, you want to take a good hard look at perldoc perlref. But if you're new to this, it might take a bit of study before the light comes on; so it did for me.)

Take another look at your own example code (a well-written example, thank you). You notice that when you execute &{$numbers{2}}; that $i is not really anywhere to be seen. Indeed, $i is out of scope. But by that time, you have defined three anonymous subroutines and put coderefs to them into the array @numbers. This is all fine and exactly what you want. You aren't keying %numbers with $i. You're keying with a literal, 2.

Let's move up to a more aggressive closure demo:

#!/usr/bin/perl use strict; use warnings; sub make_stepper { my $step = shift; my $i ; my $stepper = sub { my $usr_int = shift; my $j ; $i++; $j++; $usr_int *= $step; print '$i: ' , $i , "\t", '$j: ' , $j , "\t", '$usr_int: ' , $usr_int , "\t", "\n" ; }; return $stepper; }; print "Double: \n"; my $double = make_stepper( 2 ); &$double( 13 ); &$double( 22 ); print "\n"; print "Triple: \n"; my $triple = make_stepper( 3 ); &$triple( 13 ); print "\n"; print "Quadle: \n"; my $quadle = make_stepper( 4, 99 ); &$quadle( 13 ); &$quadle( 22 ); &$quadle( ); print "\n"; print "Reprise: \n"; &$double( 5 ); &$triple( 5 ); &$quadle( 5 ); __DATA__ Output: Double: $i: 1 $j: 1 $usr_int: 26 $i: 2 $j: 1 $usr_int: 44 Triple: $i: 1 $j: 1 $usr_int: 39 Quadle: $i: 1 $j: 1 $usr_int: 52 $i: 2 $j: 1 $usr_int: 88 Use of uninitialized value $usr_int in multiplication (*) at ./closure +-demo.pl line 18. $i: 3 $j: 1 $usr_int: 0 Reprise: $i: 3 $j: 1 $usr_int: 10 $i: 2 $j: 1 $usr_int: 15 $i: 4 $j: 1 $usr_int: 20 __END__

Here, $step and $stepper are enclosed in make_stepper(). Both are within the same lexical scope, so $stepper has no trouble at all making use of $step, which is shifted in whenever make_stepper() is called. Now $step goes out of scope as soon as its block terminates; but you might say it is "frozen" into the anonymous subroutine make_stepper() spits out.

Note that the second parm (99) is ignored when $quaddle is defined. This works as expected for 13 and 22; when $quaddle is called with no parameters, a warning is raised (and at the correct line of the code, too). This is what you want! The definition of $stepper is just that: a definition. It doesn't execute until instanced and called.

Take a look at the outputs of $i and $j. One might naively think both would be incremented.

But $j is not incremented from call to call; it goes out of scope at the end of the $stepper sub declaration and is never seen again. Each run of any of the instances creates a fresh $j, increments it to 1, prints it, and promptly forgets it.

Much more interesting is $i. This doesn't keep track of how many steppers have been made; rather it tells how often each one has been called. Note that each instance has its own counter. Think about this and see if you can tell why. Can you modify this demo to add a counter that does track how many steppers have been instanced?

Besides perldoc perlref, you might also want to take a look at Perl 5 Wiki and Perl.com on closures.


In reply to Re: Constant value in anonymous sub by Xiong
in thread Constant value in anonymous sub by Sewi

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.