NAME

Acme::Parataxis::Future - Single-Assignment Values for Fiber Coordination

SYNOPSIS

use v5.40;
use Acme::Parataxis qw[async fiber];
use Acme::Parataxis::Future;

my $future = Acme::Parataxis::Future->new;

async {
    # Consumer: parks until the future resolves
    fiber {
        say 'Waiting for answer...';
        my $val = $future->await;
        say "Got result: $val";
    };

    # Producer: sets the result from another fiber
    fiber {
        $future->set_result(42);
    };
};

DESCRIPTION

An Acme::Parataxis::Future represents a value that will become available at a later time. It acts as a single-assignment coordination point between fibers: producers fulfill the future with a result or error, and consumers park on it until it is ready.

Key characteristics:

  • Zero polling: Calling $future->await suspends the calling fiber in the scheduler. When set_result or set_error is called, all waiting fibers are re-enqueued onto the run queue in a single pass.

  • Single resolution: A future can be fulfilled exactly once. Attempting to call set_result or set_error on an already-ready future dies immediately.

  • Cancellable waits: Fibers parked in await() can be interrupted by with_timeout or Acme::Parataxis::CancellationToken. If interrupted, the fiber is safely unregistered from the future's waiter list, preventing stale wakeups.

  • Composable: Futures compose with Acme::Parataxis->wait_all and Acme::Parataxis->wait_any. Acme::Parataxis fiber objects themselves implement this same Future interface.

METHODS

new( )

my $fut = Acme::Parataxis::Future->new;

Constructs a new, unfulfilled future.

await( )

my $val = $fut->await;

Suspends the current fiber until the future is ready.

  • If the future is already ready, returns the result immediately without yielding.

  • If the future resolves via set_result($val), returns $val.

  • If the future fails via set_error($err), dies with $err in the awaiting fiber.

Must be called from inside a scheduled fiber (croaks otherwise).

result( )

my $val = $fut->result;

Returns the resolved value immediately. Croaks with "Future not ready" if the future is unfulfilled, or croaks with the stored error if the future failed. Unlike await(), result() does not park—use this when is_ready() is already known to be true or inside an on_ready callback.

set_result( $value )

$fut->set_result( { status => 'ok' } );

Fulfills the future with $value. Transitions is_ready to true, fires all callbacks registered via on_ready(), and wakes every fiber currently parked in await(). Dies if the future is already ready.

set_error( $error )

$fut->set_error("Connection refused");

Fails the future with $error. Transitions is_ready to true, fires all callbacks registered via on_ready(), and wakes every fiber parked in await(), where the error is rethrown. Dies if the future is already ready.

is_ready( )

if ( $fut->is_ready ) { ... }

Returns true if the future has been fulfilled (either by a result or an error).

error( )

my $err = $fut->error;

Returns the error passed to set_error, or undef if the future succeeded or is not yet ready.

on_ready( sub ($future) { ... } )

$fut->on_ready( sub ($f) {
    say "Finished with: " . ( $f->error // $f->result );
} );

Registers a callback to execute when the future resolves. The callback receives the future object as its sole argument. If the future is already ready, the callback executes immediately inline.

clear_result( )

$fut->clear_result;

Resets the future back to an unfulfilled state, clearing stored results, errors, callbacks, and waiters.

remove_waiter( $fid )

$fut->remove_waiter($fid);

Unregisters a fiber ID from the future's wake queue. Used by the scheduler when a wait is interrupted via a timeout or cancellation token.

Recipes

Bridging asynchronous callbacks to fibers

To integrate standard callback-based code with fibers, allocate a future and resolve it inside the callback:

sub fetch_async ($url) {
    my $future = Acme::Parataxis::Future->new;

    legacy_http_client()->get( $url, sub ( $status, $body ) {
        if ($status == 200) { $future->set_result($body) }
        else                { $future->set_error("HTTP $status") }
    } );

    return $future;
}

async {
    my $data = fetch_async('https://cpan.org')->await;
    say "Downloaded: ${\length($data)} bytes";
};

Fan-out broadcast

Multiple fibers can await the same future; when fulfilled, all waiting fibers are resumed:

my $barrier = Acme::Parataxis::Future->new;

for my $id ( 1 .. 3 ) {
    fiber {
        $barrier->await;
        say "Worker $id unblocked!";
    };
}

fiber {
    await_sleep(100);
    $barrier->set_result(1);    # wakes all 3 fibers
};

Behavior Notes

  • Exception preservation

    Exceptions passed to set_error can be plain strings or structured exception objects. They survive intact across the await boundary and rethrow in the awaiting fiber with their original class and properties preserved.

  • Futures vs. Fibers

    Every fiber spawned via fiber { ... } or spawn { ... } implements the Future interface. You can pass a fiber directly to wait_all, wait_any, await, or inspect its ->result once complete.

SEE ALSO

Acme::Parataxis, Acme::Parataxis::Actor, Acme::Parataxis::Monitor

AUTHOR

Sanko Robinson https://github.com/sanko

LICENSE

Copyright (C) Sanko Robinson.

This library is free software; you can redistribute it and/or modify it under the terms found in the Artistic License 2.