CompletableFuture.exceptionallyAsync or handleCompose

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

CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
Hello,

Recently I needed to code a completion stage that would asynchronously handle an exceptional completion of previous stage but in case of normal completion of previous stage didn't introduce another asynchronous step. I couldn't find a simple solution with CompletableFuture. Either of the following two methods were missing:

    public CompletableFuture<T> exceptionallyAsync(Function<Throwable, ? extends T> fn)

...with an overload taking Executor. These would be the async counterparts of existing "exceptionaly" method.

Similar functionality could be achieved with the following method:

    public <U> CompletableFuture<U> handleCompose(BiFunction<? super T, Throwable, ? extends CompletionStage<U>> fn)

...which would be a combination of the following two existing methods:

    public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
    public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)


The with handleCompose method one could simulate exceptionallyAsync by returning a submitted but yet uncompleted CompletableFuture in case of exceptional completion of previous stage, while returning a completed CompletableFuture in case of normal completion.

The use case I'm trying to handle is using CompletionStage as a return type of an asynchronous web service endpoint method. The thread that completes the returned CF is a scarce resource (a single Kafka IO thread). In case of normal completion I can hand such CompletableFuture to web container as it dispatches the control from it to internal thread pool when handling the response. But in case of exceptional completion, I would like to employ special thread-pool to handle the exception as this involves additional external communication.

Currently I'm using the following trick:

someCompletableFuture

            // tunnel exception as the normal result
            .handle((result, exception) -> exception != null ? exception : result)

            .thenCompose(resultOrException -> {
                if (resultOrException instanceof Throwable) {
                    return CompletableFuture.supplyAsync(() -> {
                        Throwable exc = (Throwable) resultOrException
                        // ...handle exc asynchronously...
                    });
                } else {
                    // just pass return value synchronously
                    return CompletableFuture
                        .completedFuture((ReturnType) resultOrException);
                }
            });


Has anyone else missed such method(s) on CompletableFuture too?

Regards, Peter


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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list

On 02/09/18 16:46, Peter Levart via Concurrency-interest wrote:
> ...
> Has anyone else missed such method(s) on CompletableFuture too?

Similar, but not quite the same: "CompletionStage.exceptionallyCompose"

 
http://cs.oswego.edu/pipermail/concurrency-interest/2018-March/016340.html

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
On 09/03/2018 07:13 AM, Chris Hegarty via Concurrency-interest wrote:

>
> On 02/09/18 16:46, Peter Levart via Concurrency-interest wrote:
>> ...
>> Has anyone else missed such method(s) on CompletableFuture too?
>
> Similar, but not quite the same: "CompletionStage.exceptionallyCompose"
>
>
> http://cs.oswego.edu/pipermail/concurrency-interest/2018-March/016340.html
>

Yes, the last time we discussed related issues, we were left stalled in
indecision. Adding exceptionallyCompose seems to be the best single
method to add, but still might not cover enough cases that arise in
practice; for example those that inspect the exception type, and
different async usages.

On the one hand, people can write their own methods for such cases using
whenComplete and/or handle. On the other hand, the constructions are not
at all obvious, and cannot easily be written in a way that allows them
to be used in fluent style. Any further thoughts would be welcome.

-Doug


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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list


On Mon, Sep 3, 2018 at 4:42 AM, Doug Lea via Concurrency-interest <[hidden email]> wrote:

On the one hand, people can write their own methods for such cases using
whenComplete and/or handle. On the other hand, the constructions are not
at all obvious, and cannot easily be written in a way that allows them
to be used in fluent style. Any further thoughts would be welcome.

People keep looking at the methods in CompletableFuture and rediscovering the 2 missing exceptionallyAsync methods.  And there's no hint in the sources as to why they were omitted (even I don't know - I've probably forgotten). 

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
On 09/03/2018 11:48 AM, Martin Buchholz wrote:
> People keep looking at the methods in CompletableFuture and
> rediscovering the 2 missing exceptionallyAsync methods.
I added methods to cover all variants of exceptionally{Compose}{Async}:

 exceptionally(Function<Throwable, ? extends T> f) // already exists
 exceptionallyAsync(Function<Throwable, ? extends T> f);
 exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
 exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> f);
 exceptionallyComposeAsync(Function<Throwable, ? extends
CompletionStage<T>> f);
 exceptionallyComposeAsync(Function<Throwable, ? extends
CompletionStage<T>> f, Executor e);

These target the next jdk release (12; too late for 11). For javadocs,
see
http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html

These are all declared in the CompletionStage interface. They are
directly implemented in CompletableFuture. They are default-implemented
in CompletionStage in terms of toCompletableFuture, because a concrete
CompletionStage instance is required. If some  CompletionStage
implementation class chooses not to implement toCompletableFuture to
actually return one, and also chooses not to implement these new
methods, the default implementation will fail. However, this is
presumably what anyone designing such an implementation would want.

Comments welcome as always.

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
We don't have any infrastructure for testing default methods on
CompletionStage - all concrete tests are for CompletableFuture.  But,
you say, those methods do nothing but delegate ...

Since exceptionally is less general than handle, It seems possible to
implement the former in terms of the latter, without
toCompletableFuture getting in the way, but I haven't tried it.  (That
is, can exceptionally be implemented as a pure convenience method?)
But then we'd have to test it.

On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
<[hidden email]> wrote:

> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>> People keep looking at the methods in CompletableFuture and
>> rediscovering the 2 missing exceptionallyAsync methods.
> I added methods to cover all variants of exceptionally{Compose}{Async}:
>
>  exceptionally(Function<Throwable, ? extends T> f) // already exists
>  exceptionallyAsync(Function<Throwable, ? extends T> f);
>  exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>  exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> f);
>  exceptionallyComposeAsync(Function<Throwable, ? extends
> CompletionStage<T>> f);
>  exceptionallyComposeAsync(Function<Throwable, ? extends
> CompletionStage<T>> f, Executor e);
>
> These target the next jdk release (12; too late for 11). For javadocs,
> see
> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>
> These are all declared in the CompletionStage interface. They are
> directly implemented in CompletableFuture. They are default-implemented
> in CompletionStage in terms of toCompletableFuture, because a concrete
> CompletionStage instance is required. If some  CompletionStage
> implementation class chooses not to implement toCompletableFuture to
> actually return one, and also chooses not to implement these new
> methods, the default implementation will fail. However, this is
> presumably what anyone designing such an implementation would want.
>
> Comments welcome as always.
>
> -Doug
> _______________________________________________
> 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.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
Hi Martin,

On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:
> We don't have any infrastructure for testing default methods on
> CompletionStage - all concrete tests are for CompletableFuture.  But,
> you say, those methods do nothing but delegate ...
>
> Since exceptionally is less general than handle, It seems possible to
> implement the former in terms of the latter, without
> toCompletableFuture getting in the way, but I haven't tried it.  (That
> is, can exceptionally be implemented as a pure convenience method?)
> But then we'd have to test it.

The problem with handle[Async] is that you choose synchronous vs.
asynchronous variant regardless of the type of completion of previous
stage (normal vs. exceptional). So you can't implement
exceptionallyAsync exactly with handleAsync. If you simply do:

default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
extends T> function) {
     return handleAsync((result, exception) -> {
         if (exception != null) {
             return function.apply(exception);
         } else {
             return result;
         }
     });
}

...then you have introduced an asynchronous stage even for normal
completion of previous stage. You may not want to usually do that as
this introduces latency to normal path.

Regards, Peter

>
> On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
> <[hidden email]> wrote:
>> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>>> People keep looking at the methods in CompletableFuture and
>>> rediscovering the 2 missing exceptionallyAsync methods.
>> I added methods to cover all variants of exceptionally{Compose}{Async}:
>>
>>   exceptionally(Function<Throwable, ? extends T> f) // already exists
>>   exceptionallyAsync(Function<Throwable, ? extends T> f);
>>   exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>>   exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> f);
>>   exceptionallyComposeAsync(Function<Throwable, ? extends
>> CompletionStage<T>> f);
>>   exceptionallyComposeAsync(Function<Throwable, ? extends
>> CompletionStage<T>> f, Executor e);
>>
>> These target the next jdk release (12; too late for 11). For javadocs,
>> see
>> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>>
>> These are all declared in the CompletionStage interface. They are
>> directly implemented in CompletableFuture. They are default-implemented
>> in CompletionStage in terms of toCompletableFuture, because a concrete
>> CompletionStage instance is required. If some  CompletionStage
>> implementation class chooses not to implement toCompletableFuture to
>> actually return one, and also chooses not to implement these new
>> methods, the default implementation will fail. However, this is
>> presumably what anyone designing such an implementation would want.
>>
>> Comments welcome as always.
>>
>> -Doug
>> _______________________________________________
>> 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.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
Thanks, Peter, I see your point.  Maybe the unconditional async is a
lesser evil than calling toCompletableFuture (all serious
implementations of CompletionStage will override).

Maybe a missing piece of low-level infrastructure is something that
combines handle and compose

return handleCompose((r, ex) -> (ex == null) ? this :
this.handleAsync((r, ex) -> fn.apply(ex))

Is there a monad theorist in the audience?

On Tue, Sep 18, 2018 at 9:06 AM, Peter Levart <[hidden email]> wrote:

> Hi Martin,
>
> On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:
>>
>> We don't have any infrastructure for testing default methods on
>> CompletionStage - all concrete tests are for CompletableFuture.  But,
>> you say, those methods do nothing but delegate ...
>>
>> Since exceptionally is less general than handle, It seems possible to
>> implement the former in terms of the latter, without
>> toCompletableFuture getting in the way, but I haven't tried it.  (That
>> is, can exceptionally be implemented as a pure convenience method?)
>> But then we'd have to test it.
>
>
> The problem with handle[Async] is that you choose synchronous vs.
> asynchronous variant regardless of the type of completion of previous stage
> (normal vs. exceptional). So you can't implement exceptionallyAsync exactly
> with handleAsync. If you simply do:
>
> default CompletionStage<T> exceptionallyAsync(Function<Throwable, ? extends
> T> function) {
>     return handleAsync((result, exception) -> {
>         if (exception != null) {
>             return function.apply(exception);
>         } else {
>             return result;
>         }
>     });
> }
>
> ...then you have introduced an asynchronous stage even for normal completion
> of previous stage. You may not want to usually do that as this introduces
> latency to normal path.
>
> Regards, Peter
>
>
>>
>> On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
>> <[hidden email]> wrote:
>>>
>>> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>>>>
>>>> People keep looking at the methods in CompletableFuture and
>>>> rediscovering the 2 missing exceptionallyAsync methods.
>>>
>>> I added methods to cover all variants of exceptionally{Compose}{Async}:
>>>
>>>   exceptionally(Function<Throwable, ? extends T> f) // already exists
>>>   exceptionallyAsync(Function<Throwable, ? extends T> f);
>>>   exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>>>   exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>>
>>> f);
>>>   exceptionallyComposeAsync(Function<Throwable, ? extends
>>> CompletionStage<T>> f);
>>>   exceptionallyComposeAsync(Function<Throwable, ? extends
>>> CompletionStage<T>> f, Executor e);
>>>
>>> These target the next jdk release (12; too late for 11). For javadocs,
>>> see
>>>
>>> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>>>
>>> These are all declared in the CompletionStage interface. They are
>>> directly implemented in CompletableFuture. They are default-implemented
>>> in CompletionStage in terms of toCompletableFuture, because a concrete
>>> CompletionStage instance is required. If some  CompletionStage
>>> implementation class chooses not to implement toCompletableFuture to
>>> actually return one, and also chooses not to implement these new
>>> methods, the default implementation will fail. However, this is
>>> presumably what anyone designing such an implementation would want.
>>>
>>> Comments welcome as always.
>>>
>>> -Doug
>>> _______________________________________________
>>> 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.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
  public static <T> CompletionStage<? extends T> exceptionallyAsync(CompletionStage<T> cs, Function<Throwable, ? extends T> fn) {
    return cs.handle((r, e) -> e == null ?
                                  cs:
                                  cs.handleAsync((_r, ex) -> fn.apply(ex))
                    ).thenCompose(r -> r);
  }

Alex


On 18 Sep 2018, at 18:27, Martin Buchholz via Concurrency-interest <[hidden email]> wrote:

Thanks, Peter, I see your point.  Maybe the unconditional async is a
lesser evil than calling toCompletableFuture (all serious
implementations of CompletionStage will override).

Maybe a missing piece of low-level infrastructure is something that
combines handle and compose

return handleCompose((r, ex) -> (ex == null) ? this :
this.handleAsync((r, ex) -> fn.apply(ex))

Is there a monad theorist in the audience?

On Tue, Sep 18, 2018 at 9:06 AM, Peter Levart <[hidden email]> wrote:
Hi Martin,

On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:

We don't have any infrastructure for testing default methods on
CompletionStage - all concrete tests are for CompletableFuture.  But,
you say, those methods do nothing but delegate ...

Since exceptionally is less general than handle, It seems possible to
implement the former in terms of the latter, without
toCompletableFuture getting in the way, but I haven't tried it.  (That
is, can exceptionally be implemented as a pure convenience method?)
But then we'd have to test it.


The problem with handle[Async] is that you choose synchronous vs.
asynchronous variant regardless of the type of completion of previous stage
(normal vs. exceptional). So you can't implement exceptionallyAsync exactly
with handleAsync. If you simply do:

default CompletionStage<T> exceptionallyAsync(Function<Throwable, ? extends
T> function) {
   return handleAsync((result, exception) -> {
       if (exception != null) {
           return function.apply(exception);
       } else {
           return result;
       }
   });
}

...then you have introduced an asynchronous stage even for normal completion
of previous stage. You may not want to usually do that as this introduces
latency to normal path.

Regards, Peter



On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
<[hidden email]> wrote:

On 09/03/2018 11:48 AM, Martin Buchholz wrote:

People keep looking at the methods in CompletableFuture and
rediscovering the 2 missing exceptionallyAsync methods.

I added methods to cover all variants of exceptionally{Compose}{Async}:

 exceptionally(Function<Throwable, ? extends T> f) // already exists
 exceptionallyAsync(Function<Throwable, ? extends T> f);
 exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
 exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>>
f);
 exceptionallyComposeAsync(Function<Throwable, ? extends
CompletionStage<T>> f);
 exceptionallyComposeAsync(Function<Throwable, ? extends
CompletionStage<T>> f, Executor e);

These target the next jdk release (12; too late for 11). For javadocs,
see

http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html

These are all declared in the CompletionStage interface. They are
directly implemented in CompletableFuture. They are default-implemented
in CompletionStage in terms of toCompletableFuture, because a concrete
CompletionStage instance is required. If some  CompletionStage
implementation class chooses not to implement toCompletableFuture to
actually return one, and also chooses not to implement these new
methods, the default implementation will fail. However, this is
presumably what anyone designing such an implementation would want.

Comments welcome as always.

-Doug
_______________________________________________
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


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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
Alex: Thanks for being  our official monad theorist.  To port that to
CompletableFuture without @SuppressWarnings, I came up with:

    public CompletableFuture<T> exceptionallyAsync(
        Function<Throwable, ? extends T> fn) {
        return handle(
            (r, ex) -> (ex == null)
            ? this
            : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
            .thenCompose(stage -> stage);
    }

which can be reused without changes for the CompletionStage version

    public default CompletionStage<T> exceptionallyAsync
        (Function<Throwable, ? extends T> fn) {
        return handle(
            (r, ex) -> (ex == null)
            ? this
            : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
            .thenCompose(stage -> stage);


On Tue, Sep 18, 2018 at 2:31 PM, Alex Otenko <[hidden email]> wrote:

>   public static <T> CompletionStage<? extends T>
> exceptionallyAsync(CompletionStage<T> cs, Function<Throwable, ? extends T>
> fn) {
>     return cs.handle((r, e) -> e == null ?
>                                   cs:
>                                   cs.handleAsync((_r, ex) -> fn.apply(ex))
>                     ).thenCompose(r -> r);
>   }
>
> Alex
>
>
> On 18 Sep 2018, at 18:27, Martin Buchholz via Concurrency-interest
> <[hidden email]> wrote:
>
> Thanks, Peter, I see your point.  Maybe the unconditional async is a
> lesser evil than calling toCompletableFuture (all serious
> implementations of CompletionStage will override).
>
> Maybe a missing piece of low-level infrastructure is something that
> combines handle and compose
>
> return handleCompose((r, ex) -> (ex == null) ? this :
> this.handleAsync((r, ex) -> fn.apply(ex))
>
> Is there a monad theorist in the audience?
>
> On Tue, Sep 18, 2018 at 9:06 AM, Peter Levart <[hidden email]>
> wrote:
>
> Hi Martin,
>
> On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:
>
>
> We don't have any infrastructure for testing default methods on
> CompletionStage - all concrete tests are for CompletableFuture.  But,
> you say, those methods do nothing but delegate ...
>
> Since exceptionally is less general than handle, It seems possible to
> implement the former in terms of the latter, without
> toCompletableFuture getting in the way, but I haven't tried it.  (That
> is, can exceptionally be implemented as a pure convenience method?)
> But then we'd have to test it.
>
>
>
> The problem with handle[Async] is that you choose synchronous vs.
> asynchronous variant regardless of the type of completion of previous stage
> (normal vs. exceptional). So you can't implement exceptionallyAsync exactly
> with handleAsync. If you simply do:
>
> default CompletionStage<T> exceptionallyAsync(Function<Throwable, ? extends
> T> function) {
>    return handleAsync((result, exception) -> {
>        if (exception != null) {
>            return function.apply(exception);
>        } else {
>            return result;
>        }
>    });
> }
>
> ...then you have introduced an asynchronous stage even for normal completion
> of previous stage. You may not want to usually do that as this introduces
> latency to normal path.
>
> Regards, Peter
>
>
>
> On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
> <[hidden email]> wrote:
>
>
> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>
>
> People keep looking at the methods in CompletableFuture and
> rediscovering the 2 missing exceptionallyAsync methods.
>
>
> I added methods to cover all variants of exceptionally{Compose}{Async}:
>
>  exceptionally(Function<Throwable, ? extends T> f) // already exists
>  exceptionallyAsync(Function<Throwable, ? extends T> f);
>  exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>  exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>>
> f);
>  exceptionallyComposeAsync(Function<Throwable, ? extends
> CompletionStage<T>> f);
>  exceptionallyComposeAsync(Function<Throwable, ? extends
> CompletionStage<T>> f, Executor e);
>
> These target the next jdk release (12; too late for 11). For javadocs,
> see
>
> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>
> These are all declared in the CompletionStage interface. They are
> directly implemented in CompletableFuture. They are default-implemented
> in CompletionStage in terms of toCompletableFuture, because a concrete
> CompletionStage instance is required. If some  CompletionStage
> implementation class chooses not to implement toCompletableFuture to
> actually return one, and also chooses not to implement these new
> methods, the default implementation will fail. However, this is
> presumably what anyone designing such an implementation would want.
>
> Comments welcome as always.
>
> -Doug
> _______________________________________________
> 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
>
>
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
“monad theorist” is too much of a title for me. I can’t bear it :-)

Then possibly you could just cast to T?

…handleAsync((r1, ex1) -> (T)fn.apply(ex1))

Alex

> On 19 Sep 2018, at 00:45, Martin Buchholz <[hidden email]> wrote:
>
> Alex: Thanks for being  our official monad theorist.  To port that to
> CompletableFuture without @SuppressWarnings, I came up with:
>
>    public CompletableFuture<T> exceptionallyAsync(
>        Function<Throwable, ? extends T> fn) {
>        return handle(
>            (r, ex) -> (ex == null)
>            ? this
>            : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
>            .thenCompose(stage -> stage);
>    }
>
> which can be reused without changes for the CompletionStage version
>
>    public default CompletionStage<T> exceptionallyAsync
>        (Function<Throwable, ? extends T> fn) {
>        return handle(
>            (r, ex) -> (ex == null)
>            ? this
>            : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
>            .thenCompose(stage -> stage);
>
>
> On Tue, Sep 18, 2018 at 2:31 PM, Alex Otenko <[hidden email]> wrote:
>>  public static <T> CompletionStage<? extends T>
>> exceptionallyAsync(CompletionStage<T> cs, Function<Throwable, ? extends T>
>> fn) {
>>    return cs.handle((r, e) -> e == null ?
>>                                  cs:
>>                                  cs.handleAsync((_r, ex) -> fn.apply(ex))
>>                    ).thenCompose(r -> r);
>>  }
>>
>> Alex
>>
>>
>> On 18 Sep 2018, at 18:27, Martin Buchholz via Concurrency-interest
>> <[hidden email]> wrote:
>>
>> Thanks, Peter, I see your point.  Maybe the unconditional async is a
>> lesser evil than calling toCompletableFuture (all serious
>> implementations of CompletionStage will override).
>>
>> Maybe a missing piece of low-level infrastructure is something that
>> combines handle and compose
>>
>> return handleCompose((r, ex) -> (ex == null) ? this :
>> this.handleAsync((r, ex) -> fn.apply(ex))
>>
>> Is there a monad theorist in the audience?
>>
>> On Tue, Sep 18, 2018 at 9:06 AM, Peter Levart <[hidden email]>
>> wrote:
>>
>> Hi Martin,
>>
>> On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:
>>
>>
>> We don't have any infrastructure for testing default methods on
>> CompletionStage - all concrete tests are for CompletableFuture.  But,
>> you say, those methods do nothing but delegate ...
>>
>> Since exceptionally is less general than handle, It seems possible to
>> implement the former in terms of the latter, without
>> toCompletableFuture getting in the way, but I haven't tried it.  (That
>> is, can exceptionally be implemented as a pure convenience method?)
>> But then we'd have to test it.
>>
>>
>>
>> The problem with handle[Async] is that you choose synchronous vs.
>> asynchronous variant regardless of the type of completion of previous stage
>> (normal vs. exceptional). So you can't implement exceptionallyAsync exactly
>> with handleAsync. If you simply do:
>>
>> default CompletionStage<T> exceptionallyAsync(Function<Throwable, ? extends
>> T> function) {
>>   return handleAsync((result, exception) -> {
>>       if (exception != null) {
>>           return function.apply(exception);
>>       } else {
>>           return result;
>>       }
>>   });
>> }
>>
>> ...then you have introduced an asynchronous stage even for normal completion
>> of previous stage. You may not want to usually do that as this introduces
>> latency to normal path.
>>
>> Regards, Peter
>>
>>
>>
>> On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
>> <[hidden email]> wrote:
>>
>>
>> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>>
>>
>> People keep looking at the methods in CompletableFuture and
>> rediscovering the 2 missing exceptionallyAsync methods.
>>
>>
>> I added methods to cover all variants of exceptionally{Compose}{Async}:
>>
>> exceptionally(Function<Throwable, ? extends T> f) // already exists
>> exceptionallyAsync(Function<Throwable, ? extends T> f);
>> exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>>
>> f);
>> exceptionallyComposeAsync(Function<Throwable, ? extends
>> CompletionStage<T>> f);
>> exceptionallyComposeAsync(Function<Throwable, ? extends
>> CompletionStage<T>> f, Executor e);
>>
>> These target the next jdk release (12; too late for 11). For javadocs,
>> see
>>
>> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>>
>> These are all declared in the CompletionStage interface. They are
>> directly implemented in CompletableFuture. They are default-implemented
>> in CompletionStage in terms of toCompletableFuture, because a concrete
>> CompletionStage instance is required. If some  CompletionStage
>> implementation class chooses not to implement toCompletableFuture to
>> actually return one, and also chooses not to implement these new
>> methods, the default implementation will fail. However, this is
>> presumably what anyone designing such an implementation would want.
>>
>> Comments welcome as always.
>>
>> -Doug
>> _______________________________________________
>> 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
>>
>>

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
Hi,

This is a very nice solution.

On 09/19/2018 10:20 AM, Alex Otenko wrote:
> “monad theorist” is too much of a title for me. I can’t bear it :-)
>
> Then possibly you could just cast to T?
>
> …handleAsync((r1, ex1) -> (T)fn.apply(ex1))
>
> Alex

...or help the type inference in the following way:

     default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
extends T> fn) {
         return handle(
             (r, ex) -> (ex == null)
                        ? this
                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
         ).thenCompose(Function.identity());
     }

Regards, Peter

>
>> On 19 Sep 2018, at 00:45, Martin Buchholz <[hidden email]> wrote:
>>
>> Alex: Thanks for being  our official monad theorist.  To port that to
>> CompletableFuture without @SuppressWarnings, I came up with:
>>
>>     public CompletableFuture<T> exceptionallyAsync(
>>         Function<Throwable, ? extends T> fn) {
>>         return handle(
>>             (r, ex) -> (ex == null)
>>             ? this
>>             : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
>>             .thenCompose(stage -> stage);
>>     }
>>
>> which can be reused without changes for the CompletionStage version
>>
>>     public default CompletionStage<T> exceptionallyAsync
>>         (Function<Throwable, ? extends T> fn) {
>>         return handle(
>>             (r, ex) -> (ex == null)
>>             ? this
>>             : handleAsync((r1, ex1) -> { T t = fn.apply(ex1); return t; }))
>>             .thenCompose(stage -> stage);
>>
>>
>> On Tue, Sep 18, 2018 at 2:31 PM, Alex Otenko <[hidden email]> wrote:
>>>   public static <T> CompletionStage<? extends T>
>>> exceptionallyAsync(CompletionStage<T> cs, Function<Throwable, ? extends T>
>>> fn) {
>>>     return cs.handle((r, e) -> e == null ?
>>>                                   cs:
>>>                                   cs.handleAsync((_r, ex) -> fn.apply(ex))
>>>                     ).thenCompose(r -> r);
>>>   }
>>>
>>> Alex
>>>
>>>
>>> On 18 Sep 2018, at 18:27, Martin Buchholz via Concurrency-interest
>>> <[hidden email]> wrote:
>>>
>>> Thanks, Peter, I see your point.  Maybe the unconditional async is a
>>> lesser evil than calling toCompletableFuture (all serious
>>> implementations of CompletionStage will override).
>>>
>>> Maybe a missing piece of low-level infrastructure is something that
>>> combines handle and compose
>>>
>>> return handleCompose((r, ex) -> (ex == null) ? this :
>>> this.handleAsync((r, ex) -> fn.apply(ex))
>>>
>>> Is there a monad theorist in the audience?
>>>
>>> On Tue, Sep 18, 2018 at 9:06 AM, Peter Levart <[hidden email]>
>>> wrote:
>>>
>>> Hi Martin,
>>>
>>> On 09/17/2018 08:48 PM, Martin Buchholz via Concurrency-interest wrote:
>>>
>>>
>>> We don't have any infrastructure for testing default methods on
>>> CompletionStage - all concrete tests are for CompletableFuture.  But,
>>> you say, those methods do nothing but delegate ...
>>>
>>> Since exceptionally is less general than handle, It seems possible to
>>> implement the former in terms of the latter, without
>>> toCompletableFuture getting in the way, but I haven't tried it.  (That
>>> is, can exceptionally be implemented as a pure convenience method?)
>>> But then we'd have to test it.
>>>
>>>
>>>
>>> The problem with handle[Async] is that you choose synchronous vs.
>>> asynchronous variant regardless of the type of completion of previous stage
>>> (normal vs. exceptional). So you can't implement exceptionallyAsync exactly
>>> with handleAsync. If you simply do:
>>>
>>> default CompletionStage<T> exceptionallyAsync(Function<Throwable, ? extends
>>> T> function) {
>>>    return handleAsync((result, exception) -> {
>>>        if (exception != null) {
>>>            return function.apply(exception);
>>>        } else {
>>>            return result;
>>>        }
>>>    });
>>> }
>>>
>>> ...then you have introduced an asynchronous stage even for normal completion
>>> of previous stage. You may not want to usually do that as this introduces
>>> latency to normal path.
>>>
>>> Regards, Peter
>>>
>>>
>>>
>>> On Mon, Sep 17, 2018 at 9:06 AM, Doug Lea via Concurrency-interest
>>> <[hidden email]> wrote:
>>>
>>>
>>> On 09/03/2018 11:48 AM, Martin Buchholz wrote:
>>>
>>>
>>> People keep looking at the methods in CompletableFuture and
>>> rediscovering the 2 missing exceptionallyAsync methods.
>>>
>>>
>>> I added methods to cover all variants of exceptionally{Compose}{Async}:
>>>
>>> exceptionally(Function<Throwable, ? extends T> f) // already exists
>>> exceptionallyAsync(Function<Throwable, ? extends T> f);
>>> exceptionallyAsync(Function<Throwable, ? extends T> f, Executor e);
>>> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>>
>>> f);
>>> exceptionallyComposeAsync(Function<Throwable, ? extends
>>> CompletionStage<T>> f);
>>> exceptionallyComposeAsync(Function<Throwable, ? extends
>>> CompletionStage<T>> f, Executor e);
>>>
>>> These target the next jdk release (12; too late for 11). For javadocs,
>>> see
>>>
>>> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java.base/java/util/concurrent/CompletionStage.html
>>>
>>> These are all declared in the CompletionStage interface. They are
>>> directly implemented in CompletableFuture. They are default-implemented
>>> in CompletionStage in terms of toCompletableFuture, because a concrete
>>> CompletionStage instance is required. If some  CompletionStage
>>> implementation class chooses not to implement toCompletableFuture to
>>> actually return one, and also chooses not to implement these new
>>> methods, the default implementation will fail. However, this is
>>> presumably what anyone designing such an implementation would want.
>>>
>>> Comments welcome as always.
>>>
>>> -Doug
>>> _______________________________________________
>>> 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
>>>
>>>

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On Wed, Sep 19, 2018 at 1:20 AM, Alex Otenko <[hidden email]> wrote:
> “monad theorist” is too much of a title for me. I can’t bear it :-)

I'll try to adjust my worship rites!

> Then possibly you could just cast to T?
>
> …handleAsync((r1, ex1) -> (T)fn.apply(ex1))

We try hard to avoid casts and the ugly @SuppressWarning that goes with them.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On Wed, Sep 19, 2018 at 1:49 AM, Peter Levart <[hidden email]> wrote:

>
> ...or help the type inference in the following way:
>
>     default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
> extends T> fn) {
>         return handle(
>             (r, ex) -> (ex == null)
>                        ? this
>                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
>         ).thenCompose(Function.identity());
>     }

Thanks!  This one's a winner!
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On 09/19/2018 04:49 AM, Peter Levart wrote:

> ...or help the type inference in the following way:
>
>     default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
> extends T> fn) {
>         return handle(
>             (r, ex) -> (ex == null)
>                        ? this
>                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
>         ).thenCompose(Function.identity());
>     }
>

This is a handy trick. I had mistaken inability to infer type as a need
for using a concrete type. Further simplifying using thenApplyAsync:

        return handle((r, ex) -> (ex == null) ? this
                      : this.<T>thenApplyAsync(x -> fn.apply(ex)))
            .thenCompose(Function.identity());

Something similar works with exceptionallyCompose:

     public default CompletionStage<T> exceptionallyCompose
        (Function<Throwable, ? extends CompletionStage<T>> fn) {
        return handle((r, ex) -> (ex == null) ? this : fn.apply(ex))
            .thenCompose(Function.identity());
    }

I haven't found a nice way yet to do so with exceptionallyComposeAsync.
Assuming we do, these would all make for less surprising default
implementations, but add enough overhead vs direct implementations that
CompletionStage authors would be motivated to override.

We'll also need to add separate default-implementation tests to TCK,
which will take some work.

-Doug

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list

> On 19 Sep 2018, at 15:40, Doug Lea via Concurrency-interest <[hidden email]> wrote:
>
> On 09/19/2018 04:49 AM, Peter Levart wrote:
>> ...or help the type inference in the following way:
>>
>>     default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
>> extends T> fn) {
>>         return handle(
>>             (r, ex) -> (ex == null)
>>                        ? this
>>                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
>>         ).thenCompose(Function.identity());
>>     }
>>
>
> This is a handy trick. I had mistaken inability to infer type as a need
> for using a concrete type. Further simplifying using thenApplyAsync:
>
>        return handle((r, ex) -> (ex == null) ? this
>                      : this.<T>thenApplyAsync(x -> fn.apply(ex)))
>            .thenCompose(Function.identity());
>

Will thenApplyAsync apply in exceptional case? I don’t think it will?


Alex



> Something similar works with exceptionallyCompose:
>
>     public default CompletionStage<T> exceptionallyCompose
>        (Function<Throwable, ? extends CompletionStage<T>> fn) {
>        return handle((r, ex) -> (ex == null) ? this : fn.apply(ex))
>            .thenCompose(Function.identity());
>    }
>
> I haven't found a nice way yet to do so with exceptionallyComposeAsync.
> Assuming we do, these would all make for less surprising default
> implementations, but add enough overhead vs direct implementations that
> CompletionStage authors would be motivated to override.
>
> We'll also need to add separate default-implementation tests to TCK,
> which will take some work.
>
> -Doug
>
> _______________________________________________
> 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.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list


On 09/19/2018 04:40 PM, Doug Lea wrote:

> On 09/19/2018 04:49 AM, Peter Levart wrote:
>> ...or help the type inference in the following way:
>>
>>      default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
>> extends T> fn) {
>>          return handle(
>>              (r, ex) -> (ex == null)
>>                         ? this
>>                         : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
>>          ).thenCompose(Function.identity());
>>      }
>>
> This is a handy trick. I had mistaken inability to infer type as a need
> for using a concrete type. Further simplifying using thenApplyAsync:
>
>          return handle((r, ex) -> (ex == null) ? this
>                        : this.<T>thenApplyAsync(x -> fn.apply(ex)))
>              .thenCompose(Function.identity());
>
> Something similar works with exceptionallyCompose:
>
>       public default CompletionStage<T> exceptionallyCompose
>          (Function<Throwable, ? extends CompletionStage<T>> fn) {
>          return handle((r, ex) -> (ex == null) ? this : fn.apply(ex))
>              .thenCompose(Function.identity());
>      }
>
> I haven't found a nice way yet to do so with exceptionallyComposeAsync.

What about continuing with the nesting fashion:

     default CompletionStage<T>
exceptionallyComposeAsync(Function<Throwable, ? extends
CompletionStage<T>> fn) {
         return handle(
             (r, ex) -> (ex == null)
                        ? this
                        : this.handleAsync((r1, ex1) -> fn.apply(ex1))
                              .thenCompose(Function.identity())
         ).thenCompose(Function.identity());
     }


Regards, Peter

> Assuming we do, these would all make for less surprising default
> implementations, but add enough overhead vs direct implementations that
> CompletionStage authors would be motivated to override.
>
> We'll also need to add separate default-implementation tests to TCK,
> which will take some work.
>
> -Doug
>

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On 09/19/2018 11:14 AM, Alex Otenko wrote:

>
>> On 19 Sep 2018, at 15:40, Doug Lea via Concurrency-interest <[hidden email]> wrote:
>>
>> On 09/19/2018 04:49 AM, Peter Levart wrote:
>>> ...or help the type inference in the following way:
>>>
>>>     default CompletionStage<T> exceptionallyAsync(Function<Throwable, ?
>>> extends T> fn) {
>>>         return handle(
>>>             (r, ex) -> (ex == null)
>>>                        ? this
>>>                        : this.<T>handleAsync((r1, ex1) -> fn.apply(ex1))
>>>         ).thenCompose(Function.identity());
>>>     }
>>>
>>
>> This is a handy trick. I had mistaken inability to infer type as a need
>> for using a concrete type. Further simplifying using thenApplyAsync:
>>
>>        return handle((r, ex) -> (ex == null) ? this
>>                      : this.<T>thenApplyAsync(x -> fn.apply(ex)))
>>            .thenCompose(Function.identity());
>>
>
> Will thenApplyAsync apply in exceptional case? I don’t think it will?

Good point. The specs don't require it, so Peter's version is a better
choice.

-Doug

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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On 09/19/2018 11:18 AM, Peter Levart wrote:

>> I haven't found a nice way yet to do so with exceptionallyComposeAsync.
>
> What about continuing with the nesting fashion:
>
>     default CompletionStage<T>
> exceptionallyComposeAsync(Function<Throwable, ? extends
> CompletionStage<T>> fn) {
>         return handle(
>             (r, ex) -> (ex == null)
>                        ? this
>                        : this.handleAsync((r1, ex1) -> fn.apply(ex1))
>                              .thenCompose(Function.identity())
>         ).thenCompose(Function.identity());
>     }
>

Thanks. Yet another layer of wrapping, but at least it compiles!

-Doug


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

Re: CompletableFuture.exceptionallyAsync or handleCompose

JSR166 Concurrency mailing list
It’s a common strategy to reduce CompletionStage<CompletionStage<T>> to CompletionStage<T>

Alex

> On 19 Sep 2018, at 16:40, Doug Lea via Concurrency-interest <[hidden email]> wrote:
>
> On 09/19/2018 11:18 AM, Peter Levart wrote:
>
>>> I haven't found a nice way yet to do so with exceptionallyComposeAsync.
>>
>> What about continuing with the nesting fashion:
>>
>>     default CompletionStage<T>
>> exceptionallyComposeAsync(Function<Throwable, ? extends
>> CompletionStage<T>> fn) {
>>         return handle(
>>             (r, ex) -> (ex == null)
>>                        ? this
>>                        : this.handleAsync((r1, ex1) -> fn.apply(ex1))
>>                              .thenCompose(Function.identity())
>>         ).thenCompose(Function.identity());
>>     }
>>
>
> Thanks. Yet another layer of wrapping, but at least it compiles!
>
> -Doug
>
>
> _______________________________________________
> 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
12