[External] : Re: Changes to JEP 453

Ron Pressler ron.pressler at oracle.com
Tue May 23 16:02:47 UTC 2023



> On 23 May 2023, at 15:03, Remi Forax <forax at univ-mlv.fr> wrote:
> 
> If a STS has no a shutdown policy, I believe there is a missing method "result" in SubTask that works like ShutdownOnSucess.result().
> It may either return a result (SUCCESS), throw an ExceptionException (FAILED) or throw UnavailableException (UNAVAILABLE).
> Obviously, this method can be written with the current API (state() + get() or exception()) but it will be very convenient to have it, and unify how the different STSs work.

First, if there’s no policy, then we’re either dealing with an advanced user or a very simple use case, but off the bat we’re dealing with the more exceptional situation (we may require a policy after the first preview).

Second, the very use case you’re describing is not the one we’d like to encourage. If the exception is part of a successful result it should be returned, not thrown, and if it isn’t, it belongs in the phase where the scope (even without a policy) decides what its own state is. Separating successes from failures is good.

> 
> Exception transparency is orthogonal to a specific policy (or no policy), it's a way to avoid exception erasure (exception seen as a Throwable) and its wrapping into ExecutionException.
> The wrapping into ExecutionException is quite bad because make the composition of several STSs awkward because the type of the lambda submitted to a fork and the type of exception thrown by the method containing the try-with-resources with a STS are not the same.  
> 
> Exception transparency is a way to replace the wrapping ExceptionException by a more precise exception tracked by the type system enabling easier composition.

I’m confused here. An STS is used when we want to treat multiple subtasks as a unit. If the scope fails, then it fails because its policy (whether implemented as an actual subclass of STS or inline without a subclass) decides it should fail, its exception should not be any of its forks exception, and at the very least should be wrapped to include the owner thread’s stack dump. All the things you’re mentioning are there by design to support the particular use of STS. 

In particular, that the type of exception thrown by the fork and that the type of exception thrown by some result composition method are not the same is intentional; even if we had exception transparency, we wouldn't want it here, because it’s not supposed to be the same exception type (and it’s supposed to be an exception generated by the scope’s owner thread). It also couldn’t be the same exception type: What exception should, say, SoS.result throw if, out of five forks, three forks throw IOException and the two others throw some RuntimeException?

If you care about handling a particular exception type in a particular fork differently from other types, that code belongs inside the fork, because that’s where its individuality is retained. So you’d do something like:

    scope.fork(() -> {
        try { return foo(); } catch (IOException ex) { return null; }});

Now, if you get an ExecutionException, that means that the scope has failed to yield a result, and is supposed to not say anything about the forks. But if for some reason or another you wish to explore the cause of the exception further, then future enhancements to pattern matching could help; e.g. we may have `catch (ExecutionExeption(IOException ex)) { … }`. Of course you’re also free to create any exception you like in the catch block and rethrow that.

SoF.throwIfFailed, and SoS.result have variants that allow you to manipulate the type of exception thrown by the scope if you don’t like ExecutionError.

— Ron





More information about the loom-dev mailing list