CompletableFuture.whenComplete survey

classic Classic list List threaded Threaded
31 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Doug Lea
On 12/21/2015 01:12 PM, [hidden email] wrote:
> In the second survey email, the only options clearly *compatible* with the
> CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage
exceptionally completes with this exception unless this stage also completed
exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

   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();
    });

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.



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Joe Bowbeer
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.





_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Chris Purcell
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Joe Bowbeer
Some disambiguation of "this" is needed, especially when it is referring to different stages or their things.

Using input/output would help, except that it is normal in javadoc to refer to the object whose method is being invoked as "this [thing]". In the case of CompletionStage#whenComplete, "this stage" is this CompletionStage object.

Here is my stab at a clearer sentence:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception unless this stage [had|already] completed exceptionally, in which case the first exception is retained.


On Mon, Dec 21, 2015 at 12:36 PM, Chris Purcell <[hidden email]> wrote:
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Joe Bowbeer
Given that the doc leads with the statement that whenComplete "returns a new CompletionStage with the same result or exception as this stage", I think the following is sufficiently clear:

If this stage completed normally but the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception.

On Mon, Dec 21, 2015 at 1:05 PM, Joe Bowbeer <[hidden email]> wrote:
Some disambiguation of "this" is needed, especially when it is referring to different stages or their things.

Using input/output would help, except that it is normal in javadoc to refer to the object whose method is being invoked as "this [thing]". In the case of CompletionStage#whenComplete, "this stage" is this CompletionStage object.

Here is my stab at a clearer sentence:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception unless this stage [had|already] completed exceptionally, in which case the first exception is retained.


On Mon, Dec 21, 2015 at 12:36 PM, Chris Purcell <[hidden email]> wrote:
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

tpeierls
In reply to this post by Joe Bowbeer
Joe's re-wording is good, but I think could be improved by replacing "the first exception" (which still feels a bit ambiguous: do we mean first lexically in the sentence or first in execution order?) with "the exception from the already-completed stage".

On Mon, Dec 21, 2015 at 4:05 PM, Joe Bowbeer <[hidden email]> wrote:
Some disambiguation of "this" is needed, especially when it is referring to different stages or their things.

Using input/output would help, except that it is normal in javadoc to refer to the object whose method is being invoked as "this [thing]". In the case of CompletionStage#whenComplete, "this stage" is this CompletionStage object.

Here is my stab at a clearer sentence:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception unless this stage [had|already] completed exceptionally, in which case the first exception is retained.


On Mon, Dec 21, 2015 at 12:36 PM, Chris Purcell <[hidden email]> wrote:
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

Joe Bowbeer
In reply to this post by Joe Bowbeer
Continuing my prose, an additional sentence can be added specifically for the case we are voting on, replacing the final sentence with these two:

"If this stage completed normally but the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception. If this stage completed exceptionally and the supplied action encounters an exception, then the returned stage exceptionally completes with [...]"

On Mon, Dec 21, 2015 at 1:18 PM, Joe Bowbeer <[hidden email]> wrote:
Given that the doc leads with the statement that whenComplete "returns a new CompletionStage with the same result or exception as this stage", I think the following is sufficiently clear:

If this stage completed normally but the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception.

On Mon, Dec 21, 2015 at 1:05 PM, Joe Bowbeer <[hidden email]> wrote:
Some disambiguation of "this" is needed, especially when it is referring to different stages or their things.

Using input/output would help, except that it is normal in javadoc to refer to the object whose method is being invoked as "this [thing]". In the case of CompletionStage#whenComplete, "this stage" is this CompletionStage object.

Here is my stab at a clearer sentence:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception unless this stage [had|already] completed exceptionally, in which case the first exception is retained.


On Mon, Dec 21, 2015 at 12:36 PM, Chris Purcell <[hidden email]> wrote:
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey

tpeierls
Even better. Enumerating the possibilities using that parallel sentence structure makes it clearer what's going on. (Regardless of how [...] gets filled in.)

On Mon, Dec 21, 2015 at 4:49 PM, Joe Bowbeer <[hidden email]> wrote:
Continuing my prose, an additional sentence can be added specifically for the case we are voting on, replacing the final sentence with these two:

"If this stage completed normally but the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception. If this stage completed exceptionally and the supplied action encounters an exception, then the returned stage exceptionally completes with [...]"

On Mon, Dec 21, 2015 at 1:18 PM, Joe Bowbeer <[hidden email]> wrote:
Given that the doc leads with the statement that whenComplete "returns a new CompletionStage with the same result or exception as this stage", I think the following is sufficiently clear:

If this stage completed normally but the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception.

On Mon, Dec 21, 2015 at 1:05 PM, Joe Bowbeer <[hidden email]> wrote:
Some disambiguation of "this" is needed, especially when it is referring to different stages or their things.

Using input/output would help, except that it is normal in javadoc to refer to the object whose method is being invoked as "this [thing]". In the case of CompletionStage#whenComplete, "this stage" is this CompletionStage object.

Here is my stab at a clearer sentence:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with the supplied action's exception unless this stage [had|already] completed exceptionally, in which case the first exception is retained.


On Mon, Dec 21, 2015 at 12:36 PM, Chris Purcell <[hidden email]> wrote:
Perhaps a simple change from "this stage/the returned stage" to "the input stage/the output stage" would be helpful?

Chris

On Mon, 21 Dec 2015 at 19:37 Joe Bowbeer <[hidden email]> wrote:
Thanks for clarifying!

I had to read the spec several more times before I could parse that meaning, but now that I see it, it is also hard to mistake :-)

The spec talks about "this stage" and the "returned stage" and I was confused by all the "this".

In the spec wording, below, "this stage" is stage1 throwing exception1 and the "returned stage" is stage2 throwing exception2. The last phrase contains a "this exception" referring to exception2 and also a "this stage" referring to stage1, which is especially confusing.

Annotated:

"If the supplied action [action2] itself encounters an exception [exception2], then the returned stage [stage2] exceptionally completes with this exception [exception2] unless this stage [stage1] also completed exceptionally [exception1]."

I had been interpreting the final "this stage" to mean the next stage...

Given my new understanding of the spec, throwing exception1 with suppressed exception2 (a la try-with-resources) makes a lot of sense.

To be clear, is the current jdk8 behavior *not* compliant with spec?


On Mon, Dec 21, 2015 at 10:49 AM, Doug Lea <[hidden email]> wrote:
On 12/21/2015 01:12 PM, [hidden email] wrote:
In the second survey email, the only options clearly *compatible* with the
CompletionStage spec are ...

No. Here's jdk8 spec:

"If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally."

Which describes options A and B. Option B also adds as suppressed
the whenComplete exception, which is not required but not disallowed
by current spec.

Options C would comply only if the "unless" clause were dropped.

Options D and E would require more changes.

where, as a reminder...

  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();
   });

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.




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest




_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey, pass 2

Doug Lea
In reply to this post by Doug Lea

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?





_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey, pass 2

tpeierls
On Wed, Dec 23, 2015 at 7:17 AM, Doug Lea <[hidden email]> wrote:
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.

The javadocs weren't at all clear about this intention. The parallels between the handle and whenComplete javadocs made it very easy for me to see whenComplete as the void-returning version of handle (although I was struck by the oddness of the name choices). The first real doubt in my mind was introduced by Chris Purcell's comment about resource cleanup.

But given the proposed clarification of intent, and (importantly) given the argument below about avoiding behavioral modification of the CF spec, I now agree that option B (E1 with suppressed E2) is the best choice.

--tim
 

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?






_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.whenComplete survey, pass 2

Martin Buchholz-3
Software is hard.

I agree with Doug that we should change the spec to clarify that
whenComplete's action should not throw, and I'd also like to rewrite
the class doc so that handle, as the most general continuation method,
gets the top billing instead of what we have now, where handle seems
to be merely an alternative to whenComplete.

I worry that addSuppressed (magic time travel, modifying a "past
future") is not the clear winner we would like whenever changing
existing behavior.  As an example, it is possible for many futures to
use a failed future as a source.  If any of the dependent futures
fail, you have a very rare and surprising memory leak.  So I'm now
sadly inclined to leave the jdk9 behavior the same as jdk8 ("do no
harm"), but like many others I'll grumble and accept "B".  Doug should
decide.

Doug, go ahead and commit pending spec changes.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
12