STS allows to bypass any checked exceptions

forax at univ-mlv.fr forax at univ-mlv.fr
Mon May 15 13:40:58 UTC 2023



----- Original Message -----
> From: "Ron Pressler" <ron.pressler at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "loom-dev" <loom-dev at openjdk.org>
> Sent: Monday, May 15, 2023 1:18:14 AM
> Subject: Re: STS allows to bypass any checked exceptions

> P.S.
> 
> Let me explain the design choices at a higher level. We were well aware that we
> could make the API more “correct-by-construction” by making fork and join
> protected and letting each policy define its own API.

Or better provide an AbstractFlockManager (whatever the name) and let all STSs to internally delegate to that object the same way AbstractQueueSynchronizer powers the different lock APIs in java.uti.concurrent.locks;

> But that has the downside
> of hiding the commonality of structured concurrency, which we wanted to make
> clear, especially as it’s a relatively new concept, so we decided to opt for a
> common fork, and a join the returns the scope so that the idiomatic uses are:
> 
>     return scope.join().result();
> 
> or
> 
>    scope.join().throwIfFailed();
> 
> This decision meant that APIs could be used incorrectly, but doing so will
> likely result in unchecked exceptions that signify a bug in client code.

yes, but if that exception is only thrown in case of an infrequent exception, we have a problem.

> 
> The question, therefore, is not whether the API *could* be used incorrectly but
> whether it *will* frequently be used incorrectly, which is what we hope to find
> out during the preview. Keeping fork and join public but forbidding the
> instantiation of the superclass (STS) is another option that lies between the
> current API and the more extreme “correct by construction” option, where fork
> and join are also protected. For the first preview we wanted the most lenient
> option, and then we’ll choose whether (and by how much) we may want to make STS
> more constrained.

I don't disagree, having something open at an early stage of design is a good idea.
I hope that you are reading my emails as feedback from someone playing with the STS API.

> 
> — Ron

Rémi

> 
>> On 14 May 2023, at 18:42, Ron Pressler <ron.pressler at oracle.com> wrote:
>> 
>> Both are awful and the second isn’t only awful but clearly uses the API in a way
>> the documentation warns against. The purpose of STS is for the scope to not
>> handle subtasks individually but always as a unit. Therefore, exception and
>> result handling should be done collectively. However, we offer a way to get
>> individual subtasks’ results to address the specific but common case where
>> different subtasks return different types. The ISE thrown by get means one
>> thing: there’s a bug in your code because you’ve used the API incorrectly.
>> 
>> If you find your scope code interested in a particular task’s exception, you’re
>> either doing something advanced or wrong. In fact, if you’re using STS without
>> a policy you’re either wrong or advanced.
>> 
>> One decision we wanted to postpone was whether or not to force users to use a
>> policy. If real users end up doing things similar to what you’re demonstrating
>> — which I guess we'll find out during the preview — that may well be what we
>> do. We wanted to keep the option of not using a policy open for the benefit of
>> advanced users, and obviously they can use the API incorrectly (in this case —
>> intentionally). But if regular users fall into the same trap, we may choose to
>> enforce what is now merely a recommendation.
>> 
>> — Ron
>> 
>>> On 13 May 2023, at 17:33, Remi Forax <forax at univ-mlv.fr> wrote:
>>> 
>>> The more I think about the way STS/TaskHandle manages checked exceptions the
>>> less I like it.
>>> 
>>> Here is my problem:
>>> 
>>> Do you agree that this code is kind of awful ?
>>> 
>>>   static <T> T bypassCheckedException(Callable<? extends T> callable) {
>>>       try {
>>>           return callable.call();
>>>       } catch (Exception e) {
>>>           throw new IllegalStateException("task complete with exception");
>>>       }
>>>   }
>>> 
>>> so why this other one is not
>>> 
>>>   static <T> T bypassCheckedException(Callable<? extends T> callable) {
>>>       try(var sts = new StructuredTaskScope<>()) {
>>>           var task = sts.fork(callable);
>>>           try {
>>>               sts.join();
>>>           } catch (InterruptedException e) {
>>>               Thread.currentThread().interrupt();
>>>           }
>>>           return task.get();
>>>       }
>>>   }
>>> 
>>> given that it has exactly the same semantics ?
>>> 
>>> regards,
>>> Rémi


More information about the loom-dev mailing list