Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: Real life uses for closures.

by Dallaylaen (Chaplain)
on Feb 12, 2013 at 09:32 UTC ( [id://1018322]=note: print w/replies, xml ) Need Help??


in reply to Real life uses for closures.

Event loop programming.

Ever written anything with Tk or AnyEvent? Both are almost useless without closures.

The app runs as follows: something happens in the outside world (e.g. socket receives data, or user pushes button, or timer fires), and a corresponding sub is called by the event loop engine. Such a sub is called a callback.

Of course, if you only expect two or three kinds of events, there's no need for closures. However, in a real world app one needs to create callbacks on the fly, without knowing beforehand what exacly they whould do. And closures rock.

PSGI

PSGI allows returning a closure instead of immediate [200, [ header...], [body...]]. It's great if you want to answer to the user ASAP and then do some long-running stuff. Again, not useful for a hello world.

Scope guards

Suppose you need to free some resource after leaving a particular code section. One can surround the code with layers of eval's and rethrows. Or one can use a guard object (e.g. Guard) that does its work in DESTROY, no matter why it was destroyed. Very often the code passed to guard's constructor is a closure holding a reference to the resource in question.

And there are much more (class method generation, infinite sequences, etc) uses of closures. However, most of them require a rather large application/module surrounding them to prove truly useful, maybe that's why textbook examples don't look convincing.

A sub{ ... } can do, say, 95% of what string eval can, but is also perfectly controllable and predictable.

Replies are listed 'Best First'.
Re^2: Real life uses for closures.
by LanX (Saint) on Feb 12, 2013 at 11:40 UTC
    > However, in a real world app one needs to create callbacks on the fly, without knowing beforehand what exacly they whould do. And closures rock.

    Good points, I agree with you about the use cases!

    Just your definition of closures seems to be reduced to just generating anonymous functions.

    That's not the point, the main characteristic of closures is accessing variables from the outer scope at definition/generation time, most efficiently even shared between multiple closure-functions.

    So a real-world example should include shared private variables.

    Cheers Rolf

      To be honest, at the time of my writing my "definition" of closures was "functions holding refs to outer variables". I went to re-read the wikipedia article shortly after posting.

      That said, I have yet to come across a case where several functions share the same context (aside from global variables, e.g. my $foo in the beginning of a package). If I was to design something like that (especially if the context was supposed to be mutable), I would probably end up with a class. Perl is object-oriented, after all.

      An example I could imagine was several AnyEvent callback sharing the same resource guard - where resource is not released until all callbacks have either fired, or failed. But this is, again, closer to "generation of subs" then to "use of full power of closures".

        I mentioned this earlier, but might have been a little vague: Bytes::Random::Secure is a module that has both an OO and a "functions" interface. The functions interface is for simplicity, and the OO interface is for configurability. The functions interface is just a thin wrapper over a single private instantiation of the OO interface. That module only instantiates an internal-use object if one of the "functions" is used, so lazy instantiation. The functions all share the same object, once one is created. And the object must not be accessible outside of the scope of the module, so that it cannot be tampered with (easily).

        So we use a narrowly scoped lexical to hold the object, and the functions that have access to it hold closures to the object.

        A lot of strategies were tossed about before settling on this implementation. All (including this approach) have one drawback or another. This seemed to be the least nutty. As for the decision to have a module that provides two interfaces, that was because we ran out of gas on being able to provide per-caller configurability and compartmentalization without going to an object interface, and yet didn't want to break our easy to use "functions" interface.

        So this is an example of using a closure to share an object across several functions. In a way it feels a little like C programming, where "OO" means passing a handle around. Only because we get to use a closure there's no need to bother the user with some handle.


        Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1018322]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2024-04-24 17:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found