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

We all have those things that we can't just grasp despite extensive research and testing. For me, it's the real purpose and benefit of a callback. I'm asking this question in hopes someone can make it just *click*, like Randal Schwartz's book "Learning Perl Objects, References and Modules" did for references.

My main focus is on trying to understand how 'asynchronous' (non-blocking) callbacks work. I've read they are used to offput work so that the main program can continue to work. I can't find any small enough examples that make sense. I'm imagining this would be used with fork() or threading or the like, but I just can't put it all together.

Here's a tiny code snip of what I believe is a true callback, but how do I make it function in a "do something over there so I (main) can proceed with other work"?

#!/usr/bin/perl use warnings; use strict; sub callback { for my $n (1..3){ print "callback: $n\n"; sleep(1); } } sub my_caller { my ($i, $func) = @_; print "caller calling callback\n"; &$func(); } # main my_caller(10, \&callback); for my $n (10..12){ print "main: $n\n"; sleep(1) }

I know they are used in GUI programming to wait for say, a button click, but I haven't found any examples in any languages I know well enough to understand what is happening, and how.

Would anyone be kind enough as to perhaps give an example or two to help me get over this hump of confusion? I think if I understand a real-life working purpose of a callback, I can apply other aspects to their use (such as triggering different actions etc) on my own.

Thanks,

-stevieb

Replies are listed 'Best First'.
Re: Understanding callbacks (non-blocking and multi tasking)
by LanX (Saint) on Jun 13, 2015 at 15:32 UTC
    You are mixing two things: callback and asynchronous processing (in the sense of multi tasking), which work well together but are not bundled. That's why you are confused.

    First of all callbacks should be non-blocking to allow multi tasking and your sleep is blocking by definition.

    Think of callbacks as delayed execution, which are triggered by an event instead of executing things in a linear way.

    (like adding tasks to a To-do list, like post-its on your fridge)

    But it's the event management outside of the callback which allows multitasking.

    The event management is deciding how to prioritize and bundle tasks on a To-do list and checking for urgent things from the Inbox...

    (A call from hospital might be more important than repairing the lawnmower...)

    Pushing a button in a GUI is such an event, but to be able to react the main program must be waiting for such an event instead of being blocked by longer execution or a sleep.

    (you might miss telephone while working too long in the garden)

    And while it's waiting it can call other callbacks from a queue which need to guaranty to run so fast that reacting to an event isn't hindered.

    That's roughly the model of collaborative multitasking.

    In a non-collaborative model sleep is implemented in a way to freeze a callback (read thread) and return control to the event manager who can continue the frozen thread later.

    (Ideally a thread can be frozen nearly instantly after short running atomar steps, like finishing a page in a book and putting a bookmark)

    But Perl isn't optimized for the latter and would need modules like AnyEvent to do so

    HTH!

    updates

    1. callbacks are not necessarily non-blocking, they can simply be a comfortable way to define actions like in grep or File::Find . No real relation to multi threading here.

    2. you mentioned fork, thats the non-collaborative way to allow multi-tasking on the OS level. Beside overhead (the whole perl process might be copied) it also involves the need of inter process communication.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: Understanding callbacks
by RichardK (Parson) on Jun 13, 2015 at 16:25 UTC

    Have a look at Tk::UserGuide for examples of how a gui uses callbacks.

    The first example is this :-

    #!/usr/bin/perl -w use Tk; use strict; my $mw = MainWindow->new; $mw->Label(-text => 'Hello, world!')->pack; $mw->Button( -text => 'Quit', -command => sub { exit }, )->pack; MainLoop;

    The program sets up the gui then calls MainLoop and never returns, only when the user clicks on the button will the callback -command get called.

      I very much appreciate everyone's feedback in this thread, but I'm replying here as this post (after reading through the docs of Tk) showed me that I wasn't really trying to understand callbacks, but as a few stated, Event Driven Programming.

      I just didn't correlate the two so deeply, but now I fully understand the purpose of a callback in non-event driven apps (grep was a *great* example for me to grasp).

      Although I don't have any need to do GUI programming, I am going to play around with it for a while so I can grasp this event-driven thing, as I want to fully understand how it works so perhaps one day I can incorporate some of their benefits into apps I do write on a daily basis.

      Again, thanks to all the Monks who replied with such in-depth and thought-out posts to help me understand not just about callbacks, but programming at another level.

      Thanks and regards,

      -stevieb

Re: Understanding callbacks
by BrowserUk (Patriarch) on Jun 13, 2015 at 15:14 UTC

    Ignore this. I completely missed the point (asynchronous). Sorry. I'll update later when I've eaten.

    Think about grep.

    Grep is a generic routine that filters one list (which may come from an array) into another list (which may be assigned to an array).

    The callback defines how it filters the list.

    So, with no changes to the implementation of grep, this filters out even numbers: my @odds = grep{ ( $_ % 2 ) == 1 } 1 .. 100;

    and this filters out the odd numbers: my @evens = grep{ ( $_ % 2 ) == 0 } 1 .. 100;

    The callbacks: { ... }, allow a generic routine to perform multiple purposes.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

      This is a good example which is easy to understand, thanks. However, this appears to be a 'blocking' callback. I'm really hoping for an example of a 'non-blocking' one. Or is it I'm just misinterpreting the terminology here?

        The problem is that your callback is blocking too. It sleeps for one second, during which time nothing else can happen.

        An event loop will typically have listeners registered with it. When a listener hears a message that is of interest to it, the callback will be invoked. If the callback is doing work that might consume a lot of time, that callback itself may need to break its work into smaller chunks that can be registered with the event loop too, or may need to fork a process. Or both perhaps.

        Take the example of asynchronous web apps. You may have an app that listens for http requests. So that listener sits in the event loop waiting for something to happen. When a request comes in, the listener decides if the request is interesting to it (for example, did we get a get request with a useful path?). If so, it fires off the callback associated with the specific get request (this may be handled by a route, in mojolicious).

        Now maybe that get request handler needs to scrape info from example.com. The get request handler could hit the remote server and wait, during which time the application blocks. Or it could fire off a request, and then install a listener in the event loop to listen for the response from the remote server. At that point the get request handler is free to return control back to the main event loop.

        Now the main event loop continues listening for get requests, but is also listening for a response from the remote server. And when that response comes, another callback can be fired off, possibly to render the scraped content.

        So asynchronous apps that use an event loop usually have to be designed at every level to not block; to listen, react, and register callbacks that respond to events. Callbacks may still set up listeners, and may themselves install callbacks to happen.


        Dave

A reply falls below the community's threshold of quality. You may see it by logging in.