Future
Cold async futures, structured concurrency, timers, readiness, and scoped tasks.
std.future is the canonical async module. Async calls return cold
Future<T> values; work starts when a future is consumed by await or by a
structured future API.
import std.future;
async fn load() -> i32 {
return 42;
}
async fn main() {
let work: future.Future<i32> = load();
let value = await work;
assert value == 42;
}
Future<T> is move-only and must be consumed before it leaves scope. Use
std.drop(future_value) to explicitly discard a cold future without running its
body.
| Type | Purpose |
|---|---|
Future<T> | Cold async value returned by async calls and future helpers. |
Task<T> | Scoped hot runtime handle produced by structured APIs such as group.next(). |
Group<T, E> | Scoped structured-concurrency result stream. |
AsyncError | Cancelled and Timeout. |
User code cannot manually construct Task<T>. It is a scoped handle exposed by
structured APIs, not the normal async-call result.
future.ready(value), future.sleep(duration), future.yield(),
future.readable(fd), and future.writable(fd) all return cold futures.
Creating or dropping them does not touch the scheduler, timer heap, or file
descriptor readiness state.
import std.future;
import std.time;
async fn main() {
await future.yield();
await future.sleep(try time.ms(1));
let value = await future.ready(7);
assert value == 7;
}
future.readable(fd) and future.writable(fd) wait for readiness only. The
following I/O call still observes the real operating-system result.
future.yield() is a cooperative suspension point. It lets the current runtime
poll other ready work, but it does not promise fairness, starvation freedom,
exact poll counts, or a particular batching strategy.
future.all, future.race, and future.timeout are also cold until awaited.
| Function | Purpose |
|---|---|
future.all(futures...) | Start all children and wait for all of them. Child failures cancel unfinished siblings. |
future.race(futures...) | Start all children and return the first observed homogeneous child result. |
future.timeout(future, duration) | Start a child and a deadline, returning the child result or AsyncError.Timeout. |
Structured APIs that can cancel children include future.AsyncError in their
returned error set.
import std.future;
async fn a() -> i32 {
return 10;
}
async fn b() -> i32 {
return 32;
}
async fn main() {
let pair = (await future.all(a(), b())) catch { _ => (0, 0) };
assert pair[0] + pair[1] == 42;
}
Structured result selection is deterministic. Children are scanned from left to right on each poll; if multiple outcomes are visible in the same scan, the lower child slot wins.
Optimized state-machine lowering and fallback coroutine lowering must preserve results, cancellation, and exactly-once cleanup semantics. They may differ in allocation shape, poll count, and the tick that performs cleanup.
future.Group<T, E> starts each child when group.add(future) is called
inside the group scope. The error set E must include future.AsyncError.
import std.future;
async fn fetch_a() -> i32 {
return 10;
}
async fn fetch_b() -> i32 {
return 32;
}
async fn main() {
with future.Group<i32, future.AsyncError>() as group {
group.add(fetch_a());
group.add(fetch_b());
let first = try await group.next();
let second = try await group.next();
assert first != null;
assert second != null;
}
}
group.next() returns a scoped future.Task<T? throws(E)>. It must be awaited
inside the group block and cannot be returned, stored outside the block,
detached, or passed to ordinary APIs. Use group.cancel_all() to request
cancellation for unfinished children.
| Item | Shape |
|---|---|
future.ready | ready<T>(value: T) -> Future<T> |
future.sleep | sleep(duration: time.Duration) -> Future<void> |
future.yield | yield() -> Future<void> |
future.readable | readable(fd: usize) -> Future<void> |
future.writable | writable(fd: usize) -> Future<void> |
future.all | all<T...>(futures: Future<T>...) -> Future<R throws(E)> |
future.race | race<T...>(futures: Future<T>...) -> Future<T throws(E)> |
future.timeout | timeout<T>(future: Future<T throws(E)>, duration: time.Duration) -> Future<T throws(E | future.AsyncError)> |
Group.add | add(future: Future<T>) |
Group.next | next() -> Task<T? throws(E)> |
Group.cancel_all | cancel_all() |