[concurrency-interest] CompletableFuture.whenComplete survey, pass 2

Doug Lea dl at cs.oswego.edu
Wed Dec 23 07:17:04 EST 2015


Here's another attempt to resolve this issue based on the surveys and
accompanying discussions.

As the javadocs already note, method whenComplete is intended to
preserve outcomes. We should further emphasize this by adding:

      * <p> Unlike method {@link #handle}, this method is not designed
      * to translate completion outcomes, so the supplied action should
      * not throw an exception.

An exception thrown in a whenComplete action violates the intent to
preserve outcomes, so almost any policy (possibly even stating that
the effects are undefined) might be defensible. However, the one we
chose (A) allowed an exception to be swallowed, impairing diagnosis of
usage problems.  Each of the other surveyed options avoids this
problem, and each them has advantages (and votes).  The only one that
does not require behavioral modification of the CompletionStage spec
(rather than just the CompletableFuture implementation) is option B
(to add the action exception as a suppressed exception of the incoming
exception).  So this choice does not require change in any other
implementations of the interface.  Option B also got the most
"acceptable" votes (in question 2) of survey 2. Here are results
from the 29 voters. (Questions are repasted below.)

Option  Preferred Acceptable
A       1         5
B       4         18
C       8         12
D       9         17
E       4         15

(A few people skipped question 1. Also, some did not include
question 1 choice in 2. The above table is adjusted to include them.)

Options C and D got more first-choice votes, indicating that they
probably would have been better choices in the original spec. But the
pattern of votes suggests that no choice is widely agreed on as enough
better to risk an interface spec change.

Given all this, I propose we continue with option B (the current
in-progress jdk9 update) in the CompletableFuture implementation. Plus
improve the above CompletionStage spec clarification to better describe
outcomes, as suggested by Joe and others. Here's whenComplete. the
whnCompleteAsync versions are almost identical.

      * <p> Unlike method {@link #handle}, this method is not designed
      * to translate completion outcomes, so the supplied action should
      * not throw an exception. However, if it does, the following
      * rules apply: If this stage completed normally but the supplied
      * action throws an exception, then the returned stage completes
      * exceptionally with the supplied action's exception. Or, if this
      * stage completed exceptionally and the supplied action throws an
      * exception, then the returned stage completes exceptionally with
      * this stage's exception.
      *

Any objections?

-Doug

... survey 2

Q1. Given

   CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
      if (true)
         throw new FirstException();
      else
         return "A";
    });

   CompletableFuture<String> f2 = f1.whenComplete((result, exception) -> {
     if (true)
        throw new SecondException();
    });

Where "if (true)" shows the paths of interest in this question. These might 
arise from explicit error checks, programming errors, resource failures, and/or 
translated rethrows.

What should be the completed value of f2?

A. The FirstException. In other words, preserve the source outcome (only) if 
exceptional, ignoring the SecondException.

B. The FirstException, with the SecondException as its suppressed exception.  In 
other words, preserve but modify the source exception to record the SecondException.

C. The SecondException. In other words, replace the source outcome (whether it 
is exceptional or not).

D. The SecondException, with the FirstException as its suppressed exception.  In 
other words, replace the source outcome, but if exceptional, record it as a 
suppressedException of the SecondException.

E. A new CompletionException, with the FirstException as its cause and the 
SecondException as its suppressed exception. In other words, indicate that 
throwing an exception in whenComplete is a different form of error.

Q2. Even if you don't prefer them, which of the above choices are acceptable?







More information about the Concurrency-interest mailing list