Reference implementation
TomasMikula opened this issue · 0 comments
The problem with the current Future
-based implementation
Future
s don't support removing listeners. This leads to a couple of problems.
No support for cancellation
There is no way to let a Future
know that we are no longer interested in its result, not to mention to cascade that information to upstream Future
s.
Resource leaks
Some recursive programs may lead to arbitrarily long chains of Promise
s.
To illustrate the problem, let's try to define our own flatMap
method on Future
:
def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = {
val pb = Promise[B]()
fa.onComplete {
case Success(a) => pb.completeWith(f(a))
case Failure(e) => pb.failure(e)
}
pb.future
}
Now imagine an infinite chain of such flatMap
s, as in
def loop(): Future[Unit] = {
// using *our* flatMap defined above
flatMap(step()) { _ =>
loop()
}
}
def step(): Future[Unit] = ???
loop()
will create an infinite chain of Promise
s, thus leaking resources.
This problem does not occur with Future
's flatMap
method, because it has a specialized implementation that avoids building up a chain of promises by re-linking the listeners. That's something not available to client code like the Libretto implementation.
Now, Libretto uses constructs with Promise
s like the one in the above implementation of flatMap
, but not exactly flatMap
s.
Suggestion for a correct reference implementation
Avoid Scala Future
s altogether. Instead, introduce our own primitive that gives control over listeners. Also, it need not be as general purpose as Future
, but can exploit Libretto specifics, such as having exactly one listener.