The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


AE::AdHoc - Simplified interface for tests/examples of AnyEvent-related code.


This module is NOT for introducing oneself to AnyEvent, despite the mention of "simplified". More over, it REQUIRES knowledge of what a conditional variable, or simply "condvar", is. See Anyevent::Intro.

This module is NOT for building other modules, it's for running them with minimal typing.


Suppose we have a subroutine named do_stuff( @args, $subref ) that is designed to run under AnyEvent. As do_stuff may have to wait for some external events to happen, it does not return a value right away. Instead, it will call $subref->( $results ) when stuff is done.

Now we need to test do_stuff, so we set up an event loop. We also need a timer, because a test that runs forever is annoying. So the script goes like this:

    use AnyEvent;

    # set up event loop
    my $cv = AnyEvent->condvar;
    my $timer = AnyEvent->timer(
        after => 10, cb => sub { $cv->croak("Timeout"); }

    do_stuff( @args, sub{ $cv->send(shift); } );

    # run event loop, get rid of timer
    my $result = $cv->recv();
    undef $timer;

    # finally
    analyze_results( $result );

Now, the same with AE::AdHoc:

    use AE::AdHoc;

    my $result = ae_recv {
         do_stuff( @args, ae_send );
    } 10; # timeout
    analyze_results( $result );


Functions ae_recv, ae_send, ae_croak, ae_begin, ae_end, and ae_goal are exported by default.


Note: Anywhere below, $cv means AnyEvent's conditional variable responsible for current event loop. See condvar section of AnyEvent.

ae_recv { CODE; } [ $timeout ] %options;

The main entry point of the module.

Run CODE block, enter event loop and wait for $timeout seconds for callbacks set up in CODE to fire, then die. Return whatever was sent via ae_send.

$timeout must be a nonzero real number. Negative value means "run forever". $timeout=0 would be ambigous, so it's excluded.

Options may include:

  • timeout - override the $timeout parameter (one timeout MUST be present).

  • soft_timeout - Override $timeout, and don't die, but return undef instead.

Other functions in this module would die if called outside of ae_recv.

ae_send ( [@fixed_args] )

Create callback for normal event loop ending.

Returns a sub that feeds its arguments to $cv->send(). Arguments given to the function itself are prepended, as in $cv->send(@fixed_args, @callback_args).

NOTE that ae_recv will return all sent data "as is" in list context, and only first argument in scalar context.

May be called as ae_send->( ... ) if you want to stop event loop immediately (i.e. in a handcrafted callback).

ae_croak ( [$fixed_error] )

Create callback for event loop termination.

Returns a sub that feeds its first argument to $cv->croak(). If argument is given, it will be used instead.

ae_begin ( [ sub { ... } ] )


These subroutines provide ability to wait for several events to complete.

The AnyEvent's condition variable has a counter that is incremented by begin() and decreased by end(). Optionally, the begin() function may also set a callback.

Whenever the counter reaches zero, either that callback or just send() is executed on the condvar.

Note: If you do provide callback and want the event loop to stop there, consider putting ae_send->( ... ) somewhere inside the callback.

Note: ae_begin() acts at once, and does NOT return a closure. ae_end, however, returns a subroutine reference just like ae_send/ae_croak do.

See begin/end section in AnyEvent.


ae_goal( "name", @fixed_args )

Create a named callback.

When callback is created, a "goal" is set.

When such callback is called, anything passed to it is saved in a special hash as array reference (prepended with @fixed_args, if any).

When all goals are completed, the hash of results is returned by ae_recv.

If ae_send is called at some point, the list of incomplete and complete goals is still available via goals and results calls.

The goals and results are reset every time upon entering ae_recv.


Return goals not yet achieved as hash ref.


Return results of completed goals as hash ref.


ae_action { CODE } %options

Perform CODE after entering the event loop via ae_recv (a timer is used internally).

CODE will NOT run after current event loop is terminated (see ae_recv).

Options may include:

  • after - delay before code execution (in seconds, may be fractional)

  • interval - delay between code executions (in seconds, may be fractional)

  • count - how many times to execute. If zero or omitted, means unlimited execution when interval is given, and just one otherwise.


Dying within event loop is a bad idea, so we issue warnings and write errors to magic variables. It is up to the user to check these variables.

  • $AE::AdHoc::errstr - last error (as in ::DBI).

  • @AE::AdHoc::errors - all errors.

  • $AE::AdHoc::warnings - set this to false to suppress warnings.


This module is still under heavy development, and is subject to change. Feature/change requests are accepted.

Callback confinement

If event loop is entered several times, the callbacks created in one invocations will NOT fire in another. Instead, they'll issue a warning and return (see "Error handling" below).

Error message will be like ae_send at file:13 from ae_recv[1] at file:12 called in ae_recv[2] at file:117

This is done so to isolate invocations as much as possible.

However, detection of "this invocation" will go wrong if callback maker is called in a callback itself. For instance, this will always work the same:

        # ...
        callback => sub { ae_send->(@_); },
        # ...


Konstantin S. Uvarin, <khedin at>


Please report any bugs or feature requests to bug-ae-adhoc at, or through the web interface at I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.


You can find documentation for this module with the perldoc command.

    perldoc AE::AdHoc

You can also look for information at:





Copyright 2012 Konstantin S. Uvarin.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See for more information.