CompletionStage (was: Re: Loose ends: Optional -> CompletableFuture -> Eventual)

Sam Pullara sam at
Sun Jun 30 13:03:23 PDT 2013

I like the idea of the CompletionStage interface, it would be nice if
CompletableFuture was an interface as well so we could theoretically swap
out the implementation. Here are some comments on the API in general:

As I was converting a test I had written for my Promises, there seems to be
a missing method. It appears that both handle() and exceptionally() force
the Future to then succeed. So for instance, if I just want to count
failures or something else that has a side effect, there doesn't seem to be
a way to see the exception and still allow the future to pass the failure
down the line. Is that right? For example, here is what I had in promises:

    public Promise<T> onFailure(Consumer<Throwable> block) {
        return this;

Used like:

    promise.onFailure(t -> failures.incrementAndGet())

That would just call that when there was a failure. In my API,
exceptionally() is the equivalent of something I called rescue(). I ended
up writing this method to simulate it:

    private static <T> CompletableFuture<T> onFailure(CompletableFuture<T>
future, Consumer<Throwable> call) {
        CompletableFuture<T> completableFuture = new CompletableFuture<>();
        future.handle((v, t) -> {
           if (t == null) {
           } else {
           return null;
        return completableFuture;

I was also somewhat surprised to find that my RuntimeExceptions were being
wrapped in CompletionException when they are passed to handle() and
exceptionally(). I would expect them to be the actual runtime exception
thrown rather than wrapped. Because of the way handle() behaves I also
don't see something similar to "always run this no matter what" which is
called ensure() in Promise. It is often used for resource release and
counting. There is a similar implementation for ensure(). Lastly, I think
you should add select() and collect() as static methods on
CompletableFuture that return the first or all of the results from a set of

For cancellation, it doesn't look like there is any way to get the message
downstream. In promises, cancellations go the opposite direction to
exceptions which means you can react to them. In CompletionFuture it
appears that they don't propagate down to the child CompletableFutures
which meants you can't really cancel a tree of long running operations.

Another method that seems odd to me is the thenCombine/thenAcceptBoth
method but I think that is just because we don't want to introduce a Pair
class. Promises just use join() which then transforms the return value to a


On Sun, Jun 30, 2013 at 5:58 AM, Doug Lea <dl at> wrote:

> On 06/27/13 19:29, Doug Lea wrote:
>  Assuming not, I still do owe all of those people who were so
>> unhappy about tabling discussion of a read-only interface for
>> CompletableFuture another shot at it in light of the
>> fact that we've nailed down other issues whose pending
>> status was the main reason for dropping.
> The simplest possible solution to this seems to be the best.
> New interface CompletionStage extracts all and (almost) only the
> "fluent" methods from CompletableFuture. No status methods,
> result access, blocking, cancellation, etc. Which requires
> (almost) no API change to CompletableFuture either.
> The "almost" is added method toCompletableFuture(), that
> is a kind of safe-cast/conversion to enable interoperability
> among implementations. Sorta like Collection.toArray.
> As a sanity check before committing, posting on concurrency-interest,
> and trying to talk my way past deadline-sensitive
> OpenJDK integration folks, I placed at
> Any comments or suggestions would be very welcome.
> -Doug

More information about the lambda-libs-spec-observers mailing list