Futures and promises
Adapted from Wikipedia · Adventurer experience
In computer science, futures, promises, delays, and deferreds are special tools that help programs run better, especially when doing many things at once. These tools act like placeholders for results that aren’t known yet because the computer is still working on them.
The idea of a promise was first suggested in 1976 by Daniel P. Friedman and David Wise. Around the same time, in 1977, Henry Baker and Carl Hewitt introduced a similar idea called a future.
Although these terms are often used interchangeably, they can mean slightly different things. A future is like a read-only placeholder—it shows a value that will be set later. A promise, on the other hand, is like a writable container that decides the value of the future. Importantly, a future can be set by different promises, but each future can only be set once. In many cases, a future and a promise are created together, with the future holding the value and the promise being the function that sets that value. This process of setting the value is also called resolving, fulfilling, or binding the future.
Applications
Futures and promises began in functional programming to separate a value from how it is calculated. This makes computing more flexible, including doing tasks at the same time.
Later, they were used in distributed computing to reduce delays from sending messages. They also help in writing programs that can continue without waiting for steps to finish, making them easier to create.
Implicit vs. explicit
Futures can be used in two ways: implicit or explicit. In implicit use, the future gets its value like a normal reference. In explicit use, the user must call a function to get the value.
The original paper by Baker and Hewitt talked about implicit futures, which work well in the actor model and in object-oriented languages like Smalltalk. The paper by Friedman and Wise focused on explicit futures because making implicit futures work on regular computers is tricky. In actor or object-oriented languages, this can be solved by sending the future a message to add to itself and return the result. This message passing works no matter when the future finishes its calculation.
Promise pipelining
Futures can help make things faster in systems that are spread out over a network. They allow something called promise pipelining, used in languages like E and Joule.
When you use regular ways to talk between distant computers, each step must wait for a reply before moving on. This can take a lot of time.
With futures, you can start many steps at once, without waiting for each reply. This saves time and makes things work faster.
Thread-specific futures
Some programming languages, like Alice ML, have special tools called futures. These futures are tied to a specific part of the program. They can start working right away or wait until their result is needed.
In Alice ML, there are also tools called promises. Any part of the program can finish these promises. This use of promises is different from how other languages might use the same word. In Alice ML, promises work a bit differently.
Blocking vs non-blocking semantics
When we want to get the result of a future in some computer programs, we can do it in two main ways.
In some cases, we can ask for the result and wait until it is ready. This is like sending a message and waiting for a reply. This works well in systems where we only wait like this.
But sometimes, a program might try to get the result right away. When this happens, programmers have to decide what to do. They can choose to make the program stop and wait until the result is ready. Or, they can choose to say that trying to get the result this way is an error.
For example, in the C++11 programming language, a part of the program can stop and wait for the result when needed by using special commands.
Related constructs
Futures are special tools called "events" that can only finish once. Normally, events can be reset and finished many times.
In some languages, an I-var is a type of future that waits for a result before moving on. An I-structure is a group of these I-vars. Another tool, called an M-var, can be updated many times with new values. M-vars let you take or add values, and taking a value resets the M-var to start over.
There are also tools called concurrent logic variables that work like futures but can change more than once by matching values together. The dataflow variables in the language Oz work this way too. Other tools, called concurrent constraint variables, let you narrow down possible values over time and can run special tasks when new limits are added.
Relations between the expressiveness of different forms of future
In computer programming, there are different ways to handle tasks that take time to finish. One way is to use "eager thread-specific futures." These can be made from "non-thread-specific futures" by starting a new thread to calculate the result. This helps keep things simple.
Another method uses "implicit lazy thread-specific futures." These need a way to know when the result is needed for the first time. Some systems have special tools for this, like the WaitNeeded construct. By using messages between threads, one type of future can be made from another. The best approach often combines different types of futures and tools to make things work smoothly.
Evaluation strategy
Further information: Call by future
The way futures work can change: the value of a future is found at some point between when it is made and when it is needed, but we don't know exactly when. It might happen right away (eager evaluation) or only when the value is needed (lazy evaluation). Once the value is found, it is remembered and not found again, like how some tasks are saved for later use in call by need.
A lazy future always works in a lazy way: the value is only found when it is first needed, like in call by need. Lazy futures are useful in languages where the usual way is not lazy. For example, in C++11, such lazy futures can be made by using a special setting with std::async and giving the function that computes the value.
Semantics of futures in the actor model
In the actor model, a special kind of expression called a "future" works by sending a new actor to handle requests while also starting a new task. This actor checks if it already has a result. If it does, it sends the result back to the requester. If it doesn’t have the result yet, it stores the request until the result is ready.
Sometimes, futures can help run tasks at the same time. For example, adding 1 to the result of another future calculation works well. But in some cases, like checking if a number is bigger than the result of another future calculation, the task has to wait until the result is ready before it can continue.
History
The ideas behind futures and promises were first used in programming languages like MultiLisp and Act 1. Similar ideas appeared in logic programming languages such as Prolog and Concurrent ML.
In 1988, scientists Barbara Liskov and Liuba Shrira created a way to use futures to make programs faster. Others invented the same idea around 1989 for a project called Project Xanadu. After the year 2000, many popular programming languages started to include futures and promises to help make programs respond quickly and work well on the web.
List of implementations
Some programming languages have special tools to help manage tasks that happen at the same time. These tools are called futures, promises, and similar names. They work like placeholders for results that aren’t known yet because the work isn’t finished.
Many languages include these tools or have extra libraries for them. For example:
- C++ starting with C++11 uses
std::futureandstd::promise - Dart uses
FutureandCompleterclasses withawaitandasynckeywords - JavaScript added support in ECMAScript 2015, with
asyncandawaitsince ECMAScript 2017 - Python added support in version 3.2, with
asyncandawaitin Python 3.5 - Scala uses the scala.concurrent package
Other languages also have libraries that add these tools, such as Java, Lua, and Ruby, among many others.
Futures can also be created using special programming methods called coroutines or generators. They can also be made using channels, which are like pathways for passing information between parts of a program.
Main article: Channel (programming)
Related articles
This article is a child-friendly adaptation of the Wikipedia article on Futures and promises, available under CC BY-SA 4.0.
Safekipedia