Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

Re^2: regarding 1.02 (was Re: IO::Lambda: call for participation)

by tilly (Archbishop)
on Jan 14, 2009 at 06:11 UTC ( #736144=note: print w/replies, xml ) Need Help??

in reply to Re: regarding 1.02 (was Re: IO::Lambda: call for participation)
in thread IO::Lambda: call for participation

I thought it should be read differently, then I read it more carefully and I agree with your reading. But since seeing the same thing said multiple ways often helps, let me present it my way. First merlyn's example, formatted differently.
lambda { context $socket; writable { print $socket "GET $url HTTP/1.0\r\n\r\n"; my $buf = ''; readable { my $n = sysread( $socket, $buf, 1024, length($buf)); return "read error:$!" unless defined $n; return $buf unless $n; again; }; }; };
Here it is again with comments stating what each piece does according to my understanding.
# This sets up one of many parallel closures that process # in parallel. It will be called at the start. lambda { # This sets the context of what connection this happens # on. This association is remembered within the engine. context $socket; # writeable sets up a possible event to monitor, when # $socket is writeable, execute the closure. writable { # The engine discovered we can write, so do so. print $socket "GET $url HTTP/1.0\r\n\r\n"; # This variable needs to stay shared across # multiple invocations of our readable closure, so # it needs to be outside that closure. my $buf = ''; # readable registers another event to monitor - # that $socket is readable. Note that we do not # need to set the context again because when we get # here, the engine knows what context this command # took place in, and assumes the same context. readable { # This closure is executed when we can read. my $n = sysread( $socket, $buf, 1024, length($buf)); # If we return without registering a follow-up # handler, this return will be processed as the # end of this sequence of events for whoever is # waiting on us. return "read error:$!" unless defined $n; return $buf unless $n; # We're not done so we need to do this again. # Note that the engine knows that it just # called this closure because $socket was # readable, so it can infer that it is supposed # to set up a callback that will call this # closure when $socket is next readable. again; }; }; };
And here we see the reason for the nesting. You nest whenever one action is contingent on another having already happened. Given that lambda just registers a callback, and you always want to do something, somewhere, you always nest at least once. But you can nest more times.

Replies are listed 'Best First'.
Re^3: regarding 1.02 (was Re: IO::Lambda: call for participation)
by zby (Vicar) on Jan 14, 2009 at 08:21 UTC
    One thing that is still not entirely clear here is how the $socket parameter gets passed aroud - or rather: why it needs to be passed in two ways - as a shared variable in the closure and via context? Actually - maybe I know the answer - this is because the "conditions" read from the context.
      It needs to be passed in the context because the dispatch engine needs to know about $socket so it knows when to dispatch to the closure. $socket also needs to be available in the closure, so the easiest way to do that is to make it part of the closure. However if you want the context is also available in @_. It just takes more work to get it from there.
Re^3: regarding 1.02 (was Re: IO::Lambda: call for participation)
by dk (Chaplain) on Jan 14, 2009 at 21:33 UTC
    Whoa, that is a surprise, thank you! May I ask if I can copy your code comments into the documentation? If you should like to do the same to other comments or code, you are very welcome, I'd be happy with such help.
      I would be glad to have you copy my comments into the documentation. Unfortunately I have no projects that would benefit from asynchronous IO, but if I did I'd give your project a try because it looks interesting and I'm impressed with how much you have.
        The comments are added, thank you! As soon as 1.03 is out, they shall be visible in the synopsis.
Re^3: regarding 1.02 (was Re: IO::Lambda: call for participation)
by dk (Chaplain) on Jan 14, 2009 at 23:54 UTC
    The minor thing I decided not to correct, but just changed that decision: it's not quite

    This sets up one of many parallel closures that process in parallel.

    but rather

    This sets up a new lambda object with attached one of many closures that process sequentially.

    Per one lambda, only one writable will ever be executed; after it in turn registers readable, socket won't be listened for on_write events. Same is valid for readable.

      So these are really "on_next_writable" and "on_next_readable" rather than general event handlers. (Unless they are reset with again().) That's definitely different from POE, in which event handlers persist once set.

      So, conceptually, it's sort of like this (in a sort of pseudo-code and with some lexical scope differences so that the function references are explicit which I think makes the order of execution clearer):

      my ($req, $socket, $buf); sub talk { $req = shift; $socket = IO::Socket::INET-> new( PeerAddr => '', PeerPo +rt => 80); return lambda \&init; } sub init { when_writeable( $socket, \&write_handler ); } sub write_handler { send_request( $req => $socket ); when_readable( $socket, \&read_handler ); } sub read_handler { read_stuff( $socket => $buf ) or die; if ( done() ) { return $buf; } else { when_readable( $socket, \&read_handler ); } } my $q = talk( HTTP::Request-> new( GET => '') ); print $q->wait;


      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        That's definitely different from POE, in which event handlers persist once set.

        Quite correct. I didn't realize that this is a key point difference until you've noticed it - thank you! I agree, it surely is. I should emphasize that in the docs.

        And yes, the code does the right flow.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://736144]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2017-01-19 01:28 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (166 votes). Check out past polls.