Understanding Futures and Promises
A future and a promise are related objects that together move a value from one task to another.
A Value That Must Change Hands
Imagine two tasks running side by side. One of them computes something the other one needs. The first task has to get its result to the second task. This is an everyday problem in concurrent programming, and it is the situation that futures and promises were designed to solve.
What do you think happens?
Two tasks need to pass one value between them. Before reading on, which object do you think the producing task places its value into?
Reveal answer
A promise
The producing task places its value into a promise. The implementation then makes that value appear in the corresponding future, which is the object the reading side looks at. Notice that the producer never reaches into the future itself.
Why Tasks Need a Handoff
A value computed in one task is useful only when another task can receive it. Without a dedicated handoff, the programmer must coordinate every transfer by hand, deciding when the value is ready, where it is stored, and how the other task finds it. That coordination is easy to get wrong.
Futures and promises provide a mechanism for this exact job: moving a value from one task to another. What makes them useful is that the mechanism lets the value travel between tasks while the system takes care of the transfer itself. The programmer names the two sides of the handoff rather than scripting each step of it.
The Promise and the Future as a Linked Pair
A future and a promise are related objects that together move a value from one task to another. The promise is the object the producing task writes to. The future is the object the reading side reads from. The two are connected, so a value placed into the promise appears in the corresponding future.
The two objects have distinct roles. The promise is the write-side object, and the producing task's job ends there once the value is placed in it. The future is the read-side object, and it is where the value can be picked up. Keeping these two roles separate in your head is the key to reasoning about everything that follows.
Tracing a Value from Producer to Reader
The basic idea can be stated in three moves. First, a task that wants to pass a value to another task places that value into a promise. Second, the implementation makes the value show up in the corresponding future. Third, the value can be read from that future. The source names the launcher of the task as the usual reader.
Notice what the producing task does not do. It never has to reach into the future. Its responsibility stops at the promise. The middle step deserves attention. The source says the implementation makes the value appear in the future, but it does not describe how that happens. What you need to hold onto is the outcome: the value leaves the producing task through the promise and arrives at the future, which is the object the reading side looks at.
Following One Total Across Two Tasks
Task A computes a total of 42. Task B needs that total. Trace the path of the value 42 from Task A to Task B using a promise and a future.
- 1Identify the producer
Task A computes 42, so Task A is the producing task. It is the only side that places a value into the promise.
- 2Write to the promise
Task A places 42 into the promise. Its job for this value ends here.
- 3Implementation delivers
The implementation makes 42 appear in the corresponding future. The programmer does not write this step.
- 4Read from the future
Task B's launcher reads 42 from the future, since the launcher is the usual reader.
The value 42 leaves Task A through the promise, arrives in the future, and is read by the reading side. Task A never touched the future, and Task B never touched the promise.
Why No Lock Appears in Your Code
The defining feature of futures and promises is that they move a value between two tasks without explicit use of a lock. In a setting where you might otherwise coordinate access to shared data by acquiring and releasing a lock yourself, this mechanism removes that step from your code. You do not write the coordination; the system provides it.
Mistakes in Choosing Write and Read Targets
Most errors with futures and promises come from mixing up which object belongs to which side. The mistakes below are common ways a learner might route a value to the wrong place.
Common mistake Thinking the producing task writes to the future
What it looks likeTask A tries to place 42 directly into the future and skips the promise.
Why it failsThe producing task places its value into the promise. The future is where the value appears after the implementation moves it.
Do this insteadRoute the producer's value into the promise, and let the value arrive in the future.
Common mistake Thinking the reading side reads from the promise
What it looks likeTask B looks in the promise to find the total of 42.
Why it failsThe promise is the write-side object. The reading side looks at the future, which is where the value appears.
Do this insteadRead the value from the future.
Common mistake Expecting the producer to read back the value it wrote
What it looks likeTask A places 42 into the promise and then reads from the future to confirm it.
Why it failsThe producer's job ends at the promise. The reading side is the party that picks the value up from the future.
Do this insteadLet the reading side own the read, and keep the producer's responsibility limited to writing.
Common mistake Confusing the two objects because they are linked, so treating them as one interchangeable thing
| Question | Correct answer | Common wrong answer |
|---|---|---|
| Which object does the producing task write to? | The promise | The future |
| Which object does the reading side read from? | The future | The promise |
| Where does the value appear after the handoff? | In the future | In the promise |
| Does the producer need to read the value back? | No, its job ends at the promise | Yes, to confirm the transfer |
Write-side and read-side roles for a value moving between two tasks
Practice Tracing the Path
A producing task computes the value 7. Name the object the producer writes to, the object where the value appears, and the party that reads it.
Hints
- Start with the producer. Which object does it place its value into?
- The implementation makes the value appear in the corresponding future. Which object is that?
- The launcher of the task is the usual reader. Which object does the reader look at?
Two tasks share a value. A teammate says, the reader should write its result into the promise so the producer can pick it up from the future. Explain what is wrong with this plan, using the roles of the promise and the future.
Hints
- Reread which side of the pair is the write side and which is the read side.
- Ask which object the producer is supposed to write to, and which object the reader is supposed to read from.
Key Takeaways
- Tasks need a way to hand values to one another, and futures and promises are a mechanism built for that handoff.
- A promise is the object the producing task writes to, and the corresponding future is the object the reading side reads from.
- A value travels from the producing task into the promise, appears in the future, and is read from the future by the reader.
- The transfer happens without explicit use of a lock, because the system implements it, but the roles of the write side and the read side still matter.