FIELD NOTE / 2026.09.124 MIN READ / 5 SOURCES

Futures and Promises: Turning Asynchronous Results into Programming-Language Values

Futures and promises made asynchronous computation easier to compose by giving an unfinished result a value-like placeholder that programs could pass around before the computation completed.

Parallel programming needed a way to name results that did not exist yet

A parallel computation often starts work before its result is available. Without a language abstraction, the programmer must manually track tasks, messages, completion state and synchronization. Futures and promises changed that by representing an eventual result as an object that can be stored, passed and later resolved.

The historical importance of these abstractions is that they separate launching work from waiting for its value. That separation makes latency overlap and parallel composition part of ordinary program structure rather than a special control protocol.

A placeholder can carry a dependency through the program

Code can receive a future immediately, continue doing independent work, and block only when it actually needs the future’s value. The dependency becomes explicit in data flow.

Multilisp made futures a practical parallel-language construct

Robert Halstead’s Multilisp extended Scheme with constructs for parallel execution on multiprocessors. Its future form allowed an expression to be evaluated concurrently while the program continued, with later use of the value synchronizing as necessary.[1]

This model fit symbolic programming especially well because ordinary expressions could produce future values without requiring programmers to structure every parallel action as an explicit thread-management operation.

Touching the value performs synchronization

A future is useful because waiting can be delayed until the value is demanded. The runtime may therefore overlap independent computations automatically between creation and use.

Promises adapted the idea to asynchronous procedure calls

Barbara Liskov and Liuba Shrira’s 1988 paper described a promise type for asynchronous remote procedure calls. A caller could initiate an operation, continue running in parallel, and later obtain either the result or an exception through the promise.[2]

The design made asynchronous distributed calls feel more like typed language operations. Instead of forcing every remote interaction into callback-style control flow, the promise gave the pending result a stable place in the program’s type system.

The vocabulary evolved because similar ideas appeared in different communities

The words future, promise and eventual value have been used with overlapping meanings. Some systems distinguish a writable promise from the read-only future it fulfills; others use one term for both sides. The historical lineage is therefore conceptual rather than a single standardized interface.

Research on concurrent objects and distributed languages repeatedly returned to the same need: decouple the producer of a result from the consumer while preserving a way to synchronize, propagate errors and compose further work.

Naming conventions encode ownership

Separating promise and future can make authority explicit: one component is allowed to complete the result, while other components may only observe or depend on it.

Language runtimes turned futures into mainstream task abstractions

Java’s concurrency libraries standardized a Future interface for representing results of asynchronous computations, including operations to test completion, wait for the result and cancel work.[3]

This form made futures part of ordinary enterprise and server programming. The abstraction was no longer confined to experimental parallel languages; it became a common way to connect thread pools and task execution to typed application code.

Composable futures reduced the callback problem

A basic future is often consumed by blocking on get, but later APIs added transformations and continuations so one asynchronous result can trigger another without blocking a thread. Java’s CompletableFuture, for example, supports stages that run after completion and combinations of multiple pending computations.[4]

This moved the abstraction from ‘a handle you wait on’ toward ‘a graph of dependent asynchronous computations.’

Composition is the real scalability feature

If every future is immediately waited on, concurrency disappears. The useful pattern is to build dependency chains and let the runtime schedule ready work while unresolved dependencies remain pending.

JavaScript promises brought the model to event-driven application programming

ECMAScript standardized Promise objects as a way to represent eventual completion or failure in JavaScript. Promise chaining and later async/await syntax gave web developers a structured way to express asynchronous control flow without deeply nested callbacks.[5]

Although the execution model differs from a Multilisp multiprocessor, the conceptual bridge is direct: a program can manipulate the representation of a not-yet-available result and attach later work to its completion.

Why futures and promises belong in the history of parallel software

Futures and promises changed concurrency at the language level. Multilisp demonstrated that an unfinished parallel result could behave like a value; Liskov and Shrira showed how the idea could structure asynchronous distributed calls; mainstream runtimes then turned the abstraction into everyday API design.[1][2][3]

Their lasting contribution is a programming model in which time is partially separated from data dependency: work may begin now, the value may arrive later, and the program can remain explicit about how the two are connected.

RESEARCH / PROVENANCE

Works Cited

5 SOURCES
  1. 01
  2. 02
  3. 03
  4. 04
  5. 05

CodeHistory is a living archive. Citations document the evidence used for this edition; later evidence may refine the account.

Contribute / Corrections

Improve the record.

Use this moderated submission form to suggest a correction, provide a source, challenge a priority claim or identify a missing contributor. Submissions are treated as research leads, not automatically published comments.

Submit a research lead

Please do not submit confidential material or claims you cannot support.