sam at sampullara.com
Sun Jun 30 14:48:43 PDT 2013
On Sun, Jun 30, 2013 at 2:29 PM, Doug Lea <dl at cs.oswego.edu> wrote:
> On 06/30/13 17:00, Sam Pullara wrote:
>> They can (re)throw any exception they like when completed
>> Which I think gives you the effects you wanted in next few parags of
>> your mail?
>> This is really ugly. How many wrapping layers might I end up with? I
>> can't just
>> throw the throwable. This is a very common pattern, much more common than
>> rescue() semantics. Very rarely on failure do you want to set the result
> This is a good point. When the stage methods were part of
> CompletableFuture, it was too easy and cheap to bother:
> just call completeExceptionally in the function body.
> But maybe there should be some way to get the same effect
> using a stage method.
I'd love to see:
CompletableFuture<T> ifCompletedExceptionally(Consumer<Throwable> block);
CompletableFuture<T> whenCompleted(BiConsumer<T, Throwable> block);
The former is primarily used to do side effects like incrementing counters
and possibly implementing cancellation semantics. The latter is primarily
used like finally for cleanup.
>> Why doesn't exceptionally and handle have a CompletionException as the
>> rather than Throwable if this is the case?
> Because of that "generally" disclaimer. You can get out-of-band
> exceptions like OOME that occur while processing the stage itself.
> I do agree that it is annoying. I don't think there's a solution
> to the annoyingness.
It also turns out that completeExceptionally() doesn't wrap the throwable.
I can see this being confusing for users of the API that throwing the
exception and using completeExceptionally() dont result in the same
> For cancellation, it doesn't look like there is any way to get the
>> downstream. In promises, cancellations go the opposite direction
>> which means you can react to them. In CompletionFuture it appears
>> that they
>> don't propagate down to the child CompletableFutures
>> Yes, they do (unless an intervening handle/exceptionally.)
>> The children will fail with the same exception, but I don't see where
>> they are
>> proactively notified that they are cancelled and should stop work. Hmmm,
> Do you mean, that we should try to cancel ongoing asyncs?
> For the usual reasons, the best we can guarantee is to not run
> them if they are triggered but haven't started yet. If you want
> to do more, you have to do it yourself, for example, have some
> shared atomic sentinel that they can read. (This is the same
> issue that j.u.c has disappointed you about in the past, and
> Brian has disappointed you about in Streams. It's not that we
> don't like you(!), but no one knows of a reasonable general purpose
> solution to this, and are coming to believe that nothing will ever
> be better than relying on smart developers to roll their own
> special-purpose solutions.)
Yeah, you guys keep claiming that, while I see people with pretty general
solutions getting by just fine — for example, not having
takeWhile/takeUntil on Stream is a real black eye on the API.
Here is the scaladoc for raising a interrupt in Twitter's Future. It works
pretty well for cancellation and other communication from the top where the
bottom may not know anything about what it depends on...
* Raise the given throwable as an interrupt. Interrupts are
* one-shot and latest-interrupt wins. That is, the last interrupt
* to have been raised is delivered exactly once to the Promise
* responsible for making progress on the future (multiple such
* promises may be involved in `flatMap` chains).
* Raising an interrupt does not alter the externally observable
* state of the Future. They are used to signal to the ''producer''
* of the future's value that the result is no longer desired (for
* whatever reason given in the passed Throwable).
def raise(interrupt: Throwable)
More information about the lambda-libs-spec-observers