Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Object Methods with POE::Kernel's alarm?

by dynis (Initiate)
on Jan 19, 2009 at 22:26 UTC ( [id://737414]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all,

I'm trying to use POE's alarm/delay methods, but I would like to have it call an object method. The examples provided look like this:

POE::Session->create( inline_states => { _start => sub { $_[KERNEL]->alarm( tick => time() + 1, 0 ); }, tick => sub { print "tick $_[ARG0]\n"; $_[KERNEL]->alarm( tock => time() + 1, $_[ARG0] + 1 ); }, tock => sub { print "tock $_[ARG0]\n"; $_[KERNEL]->alarm( tick => time() + 1, $_[ARG0] + 1 ); }, } );

So here the methods called are 'tick' and 'tock', and they are delayed 1 second to create an example clock. In my method I have an object $self, so I'm trying to do something more like this...

$_[KERNEL]->alarm( $self->method => time() + 5 );

.. to wait 5 seconds before calling $self->method(). I've tried different variants using references to the object method and such, but nothing seems to work properly.

Does anyone know how to do this or can anyone provide an alternative way to delay a method call while still allowing the application to go about its business (allow POE to handle events, etc)?

Replies are listed 'Best First'.
Re: Object Methods with POE::Kernel's alarm?
by rcaputo (Chaplain) on Jan 19, 2009 at 23:50 UTC

    You can use POE::Session's "object_states" rather than (or in addition to) "inline_states". The following example will have $object handle three events: "_start" will trigger its handle_start() method, "tick" will call handle_tick() and "tock" will call handle_tock():

    my $object = Object->new(); POE::Session->create( object_states => [ $object => { _start => "handle_start", tick => "handle_tick", tock => "handle_tock", }, ], );

    Here are their hypothetical handlers. Note that we're using POE::Kernel's delay() method here. delay() is equivalent to what you're doing with alarm():

    sub handle_start { $_[KERNEL]->delay( tick => 1, 0 ); }, sub handle_tick { my ($self, $kernel, $count) = @_[OBJECT, KERNEL, ARG0]; print "tick $count\n"; $self->do_other_stuff(); $kernel->delay( tock => 1, $count + 1 ); }, tock => sub { print "tock $_[ARG0]\n"; $_[OBJECT]->do_more_stuff(); $_[KERNEL]->delay( tick => 1, $_[ARG0] + 1 ); },

    Important note: OBJECT is a constant that evaluates to $self's position within @_ (almost always zero). If a program executes my $self = shift; it will shift everything in @_ one element closer to zero. All the other constants (such as KERNEL and ARG0) would then be pointing to the wrong values within @_.

Re: Object Methods with POE::Kernel's alarm?
by kyle (Abbot) on Jan 19, 2009 at 22:38 UTC

    I'm not a big POE expert, but my quick read of the documentation suggests this:

    POE::Session->create( inline_states => { _start => sub { $_[KERNEL]->alarm( my_method => time() + 5, 0 ); }, my_method => sub { $self->method(); $_[KERNEL]->alarm( my_method => time() + 5, $_[ARG0] + 1 ); }, } );

    This would call $self->method() every five seconds ($self has to be in scope when you create the POE::Session). If this isn't what you meant, then maybe I don't understand your requirements.

Re: Object Methods with POE::Kernel's alarm?
by revdiablo (Prior) on Jan 19, 2009 at 22:46 UTC

    It looks like kyle already posted a good example of what you want, but I thought you might like a bit of explanation as to why your existing solution didn't work. Your code was:

    $_[KERNEL]->alarm( $self->method => time() + 5 );

    This will call $self->method right away, and pass its return value to $_[KERNEL]->alarm(). Then, later, POE will try to trigger an event named whatever your method returned.

    In contrast, the code kyle posted wraps the call to $self->method in an event handler that gets called when the alarm triggers. You need the wrapping to avoid calling the method too soon.

Re: Object Methods with POE::Kernel's alarm?
by Anonymous Monk on Jan 20, 2009 at 04:06 UTC
    Thanks for the help everyone! It seems like I was just going about this the wrong way, and your ideas helped me figured out the best solution.

    As it turns out, you can add states at runtime using POE like this:

    $_[KERNEL]->state( 'poe_method_name', $object, 'object_method_name' );

    I think this is what had me somewhat confused. After adding the new state, you can set a delay like this..

    $_[KERNEL]->delay( poe_method_name => 10 );

    .. which would wait 10 seconds before calling $object->object_method_name().

    For me, this was the most elegant solution, which I'm leaving here to help any fellow perlmonks who stumble upon this thread.
      Boggle! My cookie must have timed out. That was me submitting my final solution to give back to the perlmonk community. Thanks again guys!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (8)
As of 2024-04-23 11:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found