Async-Trampoline

 view release on metacpan or  search on metacpan

lib/Async/Trampoline.pm  view on Meta::CPAN

to implement complex control flow:
Instead of returning a result from a function,
we can return another function that will at some point return a result.
The trampoline keeps invoking the returned function
until a result is returned.
Importantly, such trampolines eliminate tail calls.

This programming style is powerful but inconvenient
because you tend to get callback hell.
This module implements simple Futures with an async/await syntax.
Instead of nesting the callbacks, we can now chain callbacks more easily.

This module was initially created
in order to write recursive algorithms around compiler construction:
recursive-descent parsers and recursive tree traversal.
However, it is certainly applicable to other problems as well.
The module is written in C++ to keep runtime overhead minimal.

=head2 Example: loop

Synchronous/imperative:

lib/Async/Trampoline.pm  view on Meta::CPAN

        +-- Cancelled
        +-- Resolved
            +-- Error
            +-- Value

=for test

In B<Incomplete> states, the Async will be processed in the future.
At some point, the Async will transition to a completed state.

In C<async> and C<await> callbacks,
the Async will be updated to the state of the return value of that callback.

B<Completed> states are terminal.
The Asyncs are not subject to further processing.

A B<Cancelled> Async represents an aborted computation.
They have no value.
Cancellation is not an error,
but C<run_until_completion()> will die when the Async was cancelled.
You can cancel a computation via the C<async_cancel> constructor.

t/basic.t  view on Meta::CPAN


    ok !(async_cancel)->is_value, "cancel is not value";
    ok !(async_error "error message")->is_value, "error is not value";
    ok +(async_value)->is_value, "value is value";
};

describe q(errors) => sub {
    # TODO perhaps retain async_error call location,
    # instead of throwing from run_until_completion()?

    it q(can be thrown from callbacks) => sub {
        my $file = __FILE__;

        my ($l, $async) = (__LINE__, async { die "my little error" });

        throws_ok { $async->run_until_completion }
            qr/\Amy little error at \Q$file\E line $l\.$/;

        ok $async->is_error;
    };



( run in 2.106 seconds using v1.01-cache-2.11-cpan-9b1e4054eb1 )