http://www.perlmonks.org?node_id=837669

bichonfrise74 has asked for the wisdom of the Perl Monks concerning the following question:

I got this code from this article perl.com.
sub make_counter { my $start = shift; return sub { $start++ } } my $from_ten = make_counter(10); my $from_three = make_counter(3); print $from_ten->() . "\n"; print $from_ten->() . "\n"; print $from_three->() . "\n";
I tried to read the article on the explanation of the code above but I could not figure out how it is able to 'retain/remember' the old values.
Can someone further dissect or rewrite this code to show what is exactly happening?

Replies are listed 'Best First'.
Re: Closure Explanation
by AnomalousMonk (Archbishop) on Apr 30, 2010 at 02:56 UTC

    See Closure on Closures (and also How A Function Becomes Higher Order and How To: Make An Iterator) and their various 'Reply' and 'Also' sections for applications, amplifications, etc.

    I don't think I could come up with an explanation better than the above or than those contained in standard references. If you still have problems, you might try asking specific questions – with examples, if possible!

    BTW: I put these refs. together using Super Search on 'closure'!

    Update: Closure may also be helpful.

Re: Closure Explanation
by almut (Canon) on Apr 30, 2010 at 06:22 UTC

    Just think of it this way: when a function closes over a lexical variable, that instance of the variable (and its associated storage location) won't be freed, as it normally would when the variable goes out of scope — i.e. it continues to remain accessible to the function.

    Note that you can (in theory) have more than one closure sharing the same variable instance (kind of their private global variable). Extending the Anonymous Monk's code:

    #!/usr/bin/perl sub make_counter_pair { my $start = shift; warn "lexical variable ".\$start." created"; return ( sub { warn "accessing ".\$start; $start++ }, sub { warn "accessing ".\$start; $start++ } ) } my ($c1, $c2) = make_counter_pair(10); my ($c3, $c4) = make_counter_pair(3); print $c1->() . "\n"; print $c2->() . "\n"; print $c1->() . "\n"; print $c2->() . "\n"; print $c3->() . "\n"; print $c4->() . "\n"; print $c3->() . "\n"; print $c4->() . "\n";

    would give

    lexical variable SCALAR(0x604ff0) created at ./837669.pl line 5. lexical variable SCALAR(0x6323f0) created at ./837669.pl line 5. accessing SCALAR(0x604ff0) at ./837669.pl line 8. 10 accessing SCALAR(0x604ff0) at ./837669.pl line 12. 11 accessing SCALAR(0x604ff0) at ./837669.pl line 8. 12 accessing SCALAR(0x604ff0) at ./837669.pl line 12. 13 accessing SCALAR(0x6323f0) at ./837669.pl line 8. 3 accessing SCALAR(0x6323f0) at ./837669.pl line 12. 4 accessing SCALAR(0x6323f0) at ./837669.pl line 8. 5 accessing SCALAR(0x6323f0) at ./837669.pl line 12. 6

    As you can see by looking at the addresses, each pair of closures shares one variable, so the respective value is incremented every time one of the two counter functions is called.

Re: Closure Explanation
by Anonymous Monk on Apr 30, 2010 at 02:16 UTC
    sub make_counter { my $start = shift; return sub { warn \$start; $start++ } }
Re: Closure Explanation
by Anonymous Monk on Apr 30, 2010 at 18:35 UTC
    Is callback the same as closure in Perl?
      Closure example:
      sub rtn_closure { my $i = shift; return sub { $i++ }; } # f's i starts at 5 my $f = rtn_closure(5); print $f->(),"\n"; # Prints 5 print $f->(), "\n"; # Prints 6 # g gets a separate i that starts at 10 my $g = rtn_closure(10); print $g->(), "\n"; # Prints 10 print $g->(), "\n"; # Prints 11 print $f->(), "\n"; # Prints 7
      Callback example:
      sub exec_callback { my $f = shift; $f->(); } exec_callback(sub {print "hello\n"});
      Does that help? A callback does not have to close over any variables, although it could. A closure occurs whenever a function refers to a variable in an outer scope.

      No, a callback need not be closed over any variables. A closure may be called by any means a normal function is.


      TGI says moo

        Do you have a sample code showing the difference between the two?