<div dir="ltr">I don't think STS is really a special case. The same issue happens in many other places, so - to me - it would feel very out of place that Loom itself has a different error handling mechanism. That is, there is no clearly good solution, because as Alex alluded to it on this thread: If exceptions or error values are better depends on the specific context, not technical details, if the code is parallel or not. Given my experience, most of the time you do prefer exceptions over error values. Though I would love to see a feature in Java, where a function could return an error value, and if it is not handled, then it is automatically turned into an exception.<div><br></div><div>Anyway, let me go through the problems on this small sample code:</div><div><br></div><div>```</div><div>String run() {<br> try (var scope = StructuredTaskScope.open()) {<br> var results = new ArrayList<StructuredTaskScope.Subtask<?>>();<br> results.add(scope.fork(() -> 42));<br> results.add(scope.fork(() -> {<br> throw new RuntimeException("Oh, no!");<br> }));<br><br> try {<br> scope.join();<br> } catch (InterruptedException e) {<br> // I guess cancelled?<br> throw new RuntimeException(e);<br> } catch (StructuredTaskScope.FailedException e) {<br> // ok, we will check.<br> }<br><br> return results.stream()<br> .map(result -> switch (result.state()) {<br> case SUCCESS -> "Success: " + result.get();<br> case FAILED -> "Error: " + result.exception().getMessage();<br> case UNAVAILABLE -> throw new AssertionError("But why?");<br> })<br> .collect(Collectors.joining(", "));<br> }<br>}</div><div>```</div><div><br></div><div>1. `InterruptedException`: I do think that thread interrupts are a poor way to manage cancellation. The fact that they are checked is a nightmare, because effectively almost all APIs should prepare for the fact that whatever they do might do something longer, and must be cancelled which would imply that all methods should declare `InterruptedException` (which is of course absurd). Even if STS doesn't pick up the job to bring sane cancellation into the JDK, it should wrap cancellation into a new unchecked exception like `OperationCancelledException` (or something like that). This would not be important, because if later Java decides to introduce better cancellation, then a checked exception will be practically impossible to remove from an API, while an unchecked one could be retrofitted to extend a new one.</div><div><br></div><div>2. `StructuredTaskScope.FailedException`: It might look a bit uglier than if `join` returned a boolean or something, but consider the consequence: In many cases people don't want to handle the exception, and just treat it as a (semi-)catastrophic failure, and let some generic loop retry somewhere. Now, if you made it a return value, then suddenly you made things more awkward for the common case for minor gain. Because the main issue with exceptions compared to error values is that the `try-catch` creates a scope, but it is not really an issue here.</div><div><br></div><div>3. `State.UNAVAILABLE`: Maybe a bit off-topic, but let me put it here: It is kinda evil in my opinion, because most of the time I would fetch the result after a `join` where that is an impossibility, yet its presence makes switch expressions awkward. It would be nice to have a `ResultState` with only two states `SUCCESS` or `FAILED`. Then of course, the old `State` is not necessary, because it could become just a `boolean isAvailable()` instead.</div><div><br></div><div>Anyway, if the main issue was that `join` throws an exception on failure rather than signals it through a return value (or similar), then I'm strongly against the return value, because it is not really STS relevant to deliver such a paradigm shift to the JDK, and I would not want STS delivery to be delayed just because of the requirement of introducing a new paradigm which is not directly relevant to STS.</div><div><br></div><div>Attila</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">Eric Kolotyluk <<a href="mailto:eric@kolotyluk.net">eric@kolotyluk.net</a>> ezt írta (időpont: 2025. dec. 19., P, 5:56):<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>
<div>
Hi all,<br>
<br>
I’m starting a new thread to continue a discussion that emerged
elsewhere, per mailing list etiquette, and to give the topic a clean
and traceable home.<br>
<br>
My interest here isn’t reactive to any one exchange. I’ve been
experimenting with Loom since its early iterations, and over time it
has sharpened a concern I already had: whether Java’s traditional
exception model remains the right default abstraction in a world of
structured concurrency, virtual threads, and large-scale
composition.<br>
<br>
To be clear, this is not a claim that “exceptions are broken” or
that Java should abandon them. Java’s exception system has supported
billions of lines of successful code, and I’ve used it productively
for decades. Rather, Loom makes certain trade-offs more visible —
particularly around control flow, cancellation, failure propagation,
and reasoning about lifetimes — that were easier to ignore in a
purely thread-per-task world.<br>
<br>
The core questions I’m interested in exploring are along these
lines:<br>
<ul>
<li>How do unchecked exceptions interact with structured
concurrency’s goal of making lifetimes and failure scopes
explicit?</li>
<li>Do exceptions remain the best abstraction for expected failure
in highly concurrent, compositional code?</li>
<li>Are there patterns (or emerging idioms) that Loom encourages
which mitigate long-standing concerns with exceptions — or does
Loom expose new ones?</li>
<li>More broadly, should Java be thinking in terms of additional
failure-handling tools rather than a single dominant model?</li>
</ul>
I’m not advocating a specific alternative here — just inviting a
technical discussion about whether Loom changes how we should think
about error handling, and if so, how.<br>
<br>
That said, exposure to other ecosystems (e.g., Scala, Kotlin, and
more recently Rust) has broadened how I think about failure
modeling. One thing I’ve consistently appreciated about Java is that
it tends to integrate external ideas deliberately, rather than
reflexively rejecting them or adopting them wholesale. Loom itself
is a good example of that approach.<br>
<br>
I’m interested in whether error handling deserves a similar
re-examination in light of Loom’s goals.<br>
<br>
Looking forward to the discussion.<br>
<br>
Cheers,<br>
Eric
</div>
</blockquote></div>