Checked exceptions are great. Just need to understand how to use them properly. 
I think the Swift way of addressing it is fantastic. 

> On Oct 12, 2025, at 8:28 AM, Remi Forax <[email protected]> wrote:
> 
> 
> 
> 
> From: "Jige Yu" <[email protected]>
> To: "loom-dev" <[email protected]>
> Sent: Sunday, October 12, 2025 7:32:33 AM
> Subject: Feedback on Structured Concurrency (JEP 525, 6th Preview)
> Hi Project Loom.
> 
> 
> Hello,
> 
> First and foremost, I want to express my gratitude for the effort that has 
> gone into structured concurrency. API design in this space is notoriously 
> difficult, and this feedback is offered with the greatest respect for the 
> team's work and in the spirit of collaborative refinement.
> 
> My perspective is that of a developer looking to use Structured Concurrency 
> for common, IO-intensive fan-out operations. My focus is to replace everyday 
> async callback hell, or reactive chains with something simpler and more 
> readable.
> 
> It will lack depth in the highly specialized concurrent programming area. And 
> I acknowledge this viewpoint may bias my feedback.
> 
> High-Level Impression
> 
> From this perspective, the current API feels imperative and more complex for 
> the common intended use cases than necessary. It introduces significant 
> cognitive load through its stateful nature and manual lifecycle management.
> 
> Specific Points of Concern
> 
> Stateful and Imperative API: The API imposes quite some "don't do this at 
> time X" rules. Attempting to fork() after join() leads to a runtime error; 
> forgetting to call join() is another error; and the imperative fork/join 
> sequence is more cumbersome than a declarative approach would be. None of 
> these are unmanageable though.
> 
> 
> I had a similar feeling the first time I used the API, but once you play with 
> it, it kind of make sense.
> The API can be used when all tasks are different (concurrent tasks) or when 
> all task are the same (parallel tasks), a more functional API will only work 
> with the latter.
> 
> 
> Challenging Exception Handling: The exception handling model is tricky:
> 
> Loss of Checked Exception Compile-Time Safety: FailedException is effectively 
> an unchecked wrapper that erases checked exception information at compile 
> time. Migrating from sequential, structured code to concurrent code now means 
> losing valuable compiler guarantees. 
> 
> 
> You can propagate the exceptions but it makes the API clunkier (one more type 
> variable everywhere) and do not solve the fundamental problem that you do not 
> want to merge the control flow of an exception that comes from a callable 
> with one that comes from STS.join(). By example, distinguishing if an 
> InterruptedException is raised because the main thread is interrupted or if 
> one of the callable is interrupted (and this is the same will all runtime 
> exceptions).
> 
> No Help For Exception Handling: For code that wants to catch and handle these 
> exceptions, it's the same story of using instanceof on the getCause(), again, 
> losing all compile-time safety that was available in equivalent sequential 
> code.
> 
> 
> see above
> 
> Burdensome InterruptedException Handling: The requirement for the caller to 
> handle or propagate InterruptedException from join() will add room for error 
> as handling InterruptedException is easy to get wrong: one can forget to call 
> currentThread().interrupt(). Or, if the caller decides to declare throws 
> InterruptedException, the signature propagation becomes viral.
> 
> 
> Having InterruptedException not being runtime exception is a pain. But this 
> is a pain for all blocking methods.
> And BTW, you can also wrap it into a runtime exception (usually 
> UncheckedIOException/IOError) which works better than 
> currentThread().interrupt() because you do not loose the context (the stack 
> trace) and avoid the problem of the signature propagation.
> 
> Perhaps at some point in the future, all exceptions will be runtime 
> exceptions (like in Kotlin or C#) but this is a Java problem not a problem of 
> the STS API.
> 
> 
> Default Exception Swallowing: The AnySuccessOrThrow policy swallows all 
> exceptions by default, including critical ones like NullPointerException, 
> IllegalArgumentException, or even an Error. This makes it dangerously easy to 
> mask bugs that should be highly visible. There is no straightforward 
> mechanism to inspect these suppressed exceptions or fail on specific, 
> unexpected types.
> 
> 
> The straightforward mechanism is to inspect the Subtasks that keep that 
> information (if available).
> 
> Conflated API Semantics: The StructuredTaskScope API unifies two very 
> different concurrency patterns—"gather all" (allSuccessfulOrThrow) and "race 
> to first success" (anySuccessfulResultOrThrow)—under a single class but with 
> different interaction models for the same method.
> 
> In the "gather all" pattern (allSuccessfulOrThrow), join() returns void. The 
> callsite should use subtask.get()  to retrieve results.
> 
> In the "race" pattern (anySuccessfulResultOrThrow), join() returns the result 
> (R) of the first successful subtask directly. The developer should not call 
> get() on individual subtasks. Having the join()+subtask.get() method spec'ed 
> conditionally (which method to use and how depends on the actual policy) 
> feels like a minor violation of LSP and is a source of confusion. It may be 
> an indication of premature abstraction.
> 
> 
> I kind agree on this one, i.e. i would like the semantics of when to stop the 
> STS and the semantics of getting all subtaks or not to be separated given 
> there are separated concern.
> 
> Overly Complex Customization: The StructuredTaskScope.Policy API, while 
> powerful, feels like a potential footgun. The powerful lifecycle callback 
> methods like onFork(), onComplete(), onTimeout() may lower the barrier to 
> creating intricate, framework-like abstractions that are difficult to reason 
> about and debug.
> 
> 
> yes, especially if you try to do reduce to a value (like a Collector) inside 
> the Joiner but this is called out by the documentation.
> 
> I will answer the rest of the mail, in a new message.
> 
> Rémi
> 
> 
> 

Reply via email to