[concurrency-interest] Interface CompletionStage

Doug Lea dl at cs.oswego.edu
Mon Jul 1 16:26:50 EDT 2013

Last fall there was a lot of controversy about the API for
class CompletableFuture. Some people demanded the
presence of some methods, and some people demanded the
absence of these same methods. I think it is safe to
say that everyone with strong feelings about this
was disappointed. At the time, I tabled this discussion
pending further thought about possible options.

Just barely (I hope!) before it is too late to do anything
about this, I returned try to come to a better resolution.
Here it is:

New interface CompletionStage contains (almost) only the "fluent"
methods (thenApply, etc). These are uncontroversial.
Class CompletableFuture implements CompletionStage, and
also the methods people may or may not want to
allow users to use in any layered framework. However
CompletableFuture is structured such that any subclass
can disable any of the non-CompletionStage methods
by overriding to throw UnsupoortedOperationException,
and still use it for a perfectly compliant CompletionStage
implementation. For example, for those who want/need to
disable cancel(), might write...

  class MyCompletableFuture extends CompletableFuture { ...
     public boolean cancel(...) { throw new UnsupportedOperationException(); }
   class MyCompletionStage implements CompletionStage {
     MyCompletableFuture cf ...
     // delegate all methods to cf;

And many variations like this in which you may choose to
create and use a (strictly internal) intentionally-crippled
CompletableFuture subclass, but a perfectly fine and compliant
CompletionStage implementation. Design-by-UOE is an odd extension
policy, but better than all the others I know in coping with this issue.

Very little needed to be changed to pull this off.
 From the CompletableFuture view, just a few small additions
that do not impact any existing usages:

1. Interface CompletionStage requires one more method
than just the stage-based fluent ones, toCompletableFuture()
that ensures a completely safe common currency for interoperability.
(It is safe, because it may be implemented as a new stage,
not necessarily a (casted) "return this", as it is in
CompletableFuture itself.)

2. New method CompletionStage.whenCompleted plays a role similar to
that of CompletableFuture.exceptionally but avoids a type-system
problem: Method exceptionally() relied on the availability to users of
method completeExceptionally to get the equivalent of an
exception rethrow if so desired. Without it being available
in CompletionStage, there is no sanctioned way to do this.
But whenCompleted can now be used in the rethrow case.
Also, the whenCompleted and handle methods are available
in async versions.

3. The little utility method CompletableFuture.isCompletedExceptionally
should have been there to begin with, but is now hard to
live without.

That's it. I think that these small changes will make
a big difference in how CompletableFuture can be used
as basic infrastructure for layered frameworks. And
I cannot imagine any way in which it makes things worse
for anyone. But if you do, please let me know very soon.
(But please(!) do not ask for "just one more" change or feature!)

If I don't hear any soon, I'll try to make a case for it as
a late change for JDK8.



More information about the Concurrency-interest mailing list