I was always wondering what is the magic behind the Future[T] in Scala, and finally I found no
magic but everything falling back to the old Java concurrent things. All the callback functions
are finally turned into a java.lang.Runnables and are managed by some
java.util.concurrent.Executor.
Future[T] in Scala is implemented internally with Promise[T]. The terms future and promise
are often used interchangeably, there are some differences in usage. A future is a read-only
placeholder view of a variable, while a promise is a writable, single assignment container
which sets the value of the future.
Use one sentance to discribe the implementation would be: the body of the future and all the
callbacks are essentially runnables, which use promises to store the result of the expression.
Following is the simplified version of Future[T] and Promise[T].
The heart of the Future[T] is the onComplete method, everything else is based on it.
Everytime we create a Future we create a Promise, which stores the result of the expression
by calling the complete method. The evaluation of the expression is encapsulated in a
Runnable to run in some thread managed by the executor, so the Future returns immediately.
Now, let’s look at the simplified implementation of Promise[T].
tryComplete returns false when the Promise has already been written, so that the complete
method can be called only once, or it will throw an exception, thus the single assignment
property is promised.
Finally, we get to the base of everything. Let’s go through the implementation step by step, the
simplified implementation.
A trait to be used below, you can see that sometimes Future and Promise are interchangeable.
This is the Runnable that encapsulates the callback function.
The implementation! A Promise has three states: incomplete, complete, link
to another Promise. The third state is produced under the chaining of
futures and promises.
Compressing the root is necessary for preventing memory leaks. It also benifits
subsequent calls.
When a Promise has already been completed, tryCompleteAndGetListeners will return
a null, or it will return the callback function list. If the callback function list
is not empty, then tryComplete schedule those callbacks.
If the state is a list of callbacks, it means that the Promise has not been completed
yet, thus complete it and return the list of callbacks. Return null otherwise.
When adding a callback to a Promise, if the Promise has already been completed,
we schedule the callback, otherwise, we add it into the callback list.
This is for an already completed Future, useful in future-composition, chaining.