Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Closures Explained

by Anonymous Monk
on Jul 13, 2009 at 16:00 UTC ( #779650=perlquestion: print w/replies, xml ) Need Help??

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

Hello folks,

Would anyone be able to give a clear, simplistic idea of what is a closure and what it is used for (maybe with a example). I have read the description in the Camel book 'Programming Perl' but it just doesn't seem to compute? any clarity thankfully received!

Replies are listed 'Best First'.
Re: Closures Explained
by Limbic~Region (Chancellor) on Jul 13, 2009 at 16:59 UTC
Re: Closures Explained
by jwkrahn (Monsignor) on Jul 13, 2009 at 16:08 UTC
Re: Closures Explained
by ambrus (Abbot) on Jul 13, 2009 at 19:28 UTC

    If you like to learn from books, try Mark Jason Dominus' Higher Order Perl book. You can download it in pdf form or buy a dead tree copy.

Re: Closures Explained
by sundialsvc4 (Abbot) on Jul 13, 2009 at 23:07 UTC
    “Padewan, when you need to use Closures, you will know.”

    In a word, “a closure has a memory.” That is, it has access to a set of variables and values, that are known only to itself but that are persistent (and unique) for as long as the closure itself exists.

    So, for example, I could hand you a closure that, each time you call upon it, returns a number one-greater than the number it returned the last time you called upon it. And yet, I could hand you just as many copies of that closure as I desired, and each one would exhibit that behavior.

    “Cool, huh?”

      I don't think the quote is true. If you do not know something exists (or know just the name, but do not know what the heck it actually is), you cannot know whether you need it. And you'll instead spend time finding some way to get around that.

      Enoch was right!
      Enjoy the last years of Rome.

Re: Closures Explained
by pemungkah (Priest) on Jul 14, 2009 at 19:20 UTC
    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.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://779650]
Approved by Corion
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (6)
As of 2023-03-29 09:26 GMT
Find Nodes?
    Voting Booth?
    Which type of climate do you prefer to live in?

    Results (70 votes). Check out past polls.