Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
Quick and dirty closure example:
sub counter { my $start_value = shift; return sub { return $start_value++; } }
This is a subroutine that returns a new anonymous subroutine. That new subroutine references a lexical variable in an enclosing block. Now: when the subroutine exits, normally there'd be no more references to that variable, so it would disappear. But since the newly-returned subroutine has a reference to it (remember, you're allowed to see lexicals in a scope that encloses you), the new subroutine can still use the variable, even though no other code can directly address it (yeah, we can use cpan:Padwalker or something similar, but that's not really germane to the discussion).

Anyway. We've now got this new subroutine; it's called a closure because the block that is the subroutine can reference this otherwise-invisible variable - sometimes you hear it said that the sub has closed over the lexical variable.

my $counter1 = counter(5); my $counter2 = counter(20); print $counter1->(), $counter1->(), $counter1->(),"\n"; print $counter2->(),"\n"; print $counter1->(),"\n";
and we get
567 20 8
Notice that each closure preserves its own copy of the closed-over variable.

So big deal. Hidden variable. So what?

The big deal is twofold: one, the variable is completely controlled by the closure now and its state is carried along with the closure. So You can only look at the variable via the closure's interface. Second, and this is the really useful part, calling the counter sub again with a new starting value manufactures a completely new and separate closure! So you can create as many counters as you like; they all use the same code, but each one tracks its own internal state.

One of the really useful things to use this for is being able to "half-call" a subroutine (Technically, I think this is an example of currying, but let's use "half-call" for the sake of explanation.)

Let's say you had a subroutine that you knew some of the information you'd need to call it at one point, but wouldn't know the rest of the information until later. One way to do this is to build a hash, store the data, run until you have the rest, then call the sub after looking up the appropriate data. Not too complicated, but it does clutter the flow a bit.

We could instead build a closure at the point we have the first set of data:

sub build_one { my($foo, $bar, $baz) = @_; return sub { my $quux = shift; do_something($foo, $bar, $baz, $quux); } } # Figure out first three args... push @queue, build_one($alpha, $beta, $gamma); # repeat as necessary.
We've done the first part of the call: setting up one or more closures with the information we know now and sticking them in the queue of stuff to finish later.

When we get the rest of the data we need, we just pull the closures off one by one and call them with the rest of the data.

map { $_->($last_thing) } @queue;
And we've finished off all the stuff we had queued up to do once we knew the last piece of data. There are loads more ways to use closures; this is just to point you in the direction of thinking "I can make a sub that remembers things. What can I do with that? Do I need it for this problem?"

Have the appropriate amount of fun.


In reply to Re: Closures Explained by pemungkah
in thread Closures Explained by Anonymous Monk

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



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (9)
As of 2024-03-28 09:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found