Skip to content

Q056. What is a Future?

Short Answer

A Future is a value representing a computation that may complete later. Its associated Output is produced through repeated calls to poll. poll returns Ready(output) when complete or Pending when it cannot progress now. A future is lazy: creating it does not drive the computation. It must be awaited, spawned, or otherwise polled by an executor.

Deep Dive

The essential trait is:

rust
trait Future {
    type Output;

    fn poll(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output>;
}

When returning Pending, a well-behaved future arranges for the current task's waker to be notified when another poll may make progress. poll must return quickly and must not block the executor thread.

Most code does not implement Future manually. async blocks and async fn generate futures, and .await composes them. The trait becomes important when reasoning about laziness, scheduling, pinning, cancellation, and custom asynchronous primitives.

Internal Model

A future commonly acts as a state machine. Its fields contain captured arguments, child futures, progress state, and locals that must survive suspension.

The executor owns task scheduling around the future. The future itself defines how one unit of progress is made when polled.

Example

rust
use std::future::Future;

fn creates_future() -> impl Future<Output = u64> {
    async { 21 * 2 }
}

#[tokio::main]
async fn main() {
    let future = creates_future();
    assert_eq!(future.await, 42);
}

Common Mistakes

  • Calling a future a background thread or an already-running task.
  • Blocking inside Future::poll.
  • Polling a completed future again unless its implementation explicitly permits it.

Follow-ups

  • Why does poll receive Pin<&mut Self>?
  • Who calls poll in a normal async application?
  • What contract must a future satisfy before returning Pending?

References

  • Rust Standard Library
  • Async Book