<html><body><div style="font-family: arial, helvetica, sans-serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr" data-marker="__DIVIDER__"><div data-marker="__HEADERS__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Alan Bateman" <alan.bateman@oracle.com><br><b>To: </b>"Adam Warski" <adam@warski.org>, "loom-dev" <loom-dev@openjdk.org><br><b>Sent: </b>Friday, September 26, 2025 11:20:57 AM<br><b>Subject: </b>Re: Problem report on the usage of Structured Concurrency (5th preview)<br></blockquote></div><div data-marker="__QUOTED_TEXT__"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><div class="moz-cite-prefix">On 26/09/2025 07:37, Adam Warski wrote:<br>
    </div>
    <blockquote cite="mid:85467C61-8139-4832-B3BA-BFA53061E986@warski.org">
      <pre class="moz-quote-pre">Good morning,

with the release of Java 25, I’ve attempted to migrate my virtual-thread-native, reactive-streaming-like library from Java 21 to Java 25 scopes. So far I’ve been using my own wrapper on StructuredConcurrencyScope, but with that migration I wanted to eliminate it, and just use SCS directly. However, I encountered some problems with SCS’s design; I've summarised them in a blog (<a class="moz-txt-link-freetext" href="https://softwaremill.com/critique-of-jep-505-structured-concurrency-fifth-preview" target="_blank">https://softwaremill.com/critique-of-jep-505-structured-concurrency-fifth-preview</a>), and then prompted by a discussion on Reddit that followed (<a class="moz-txt-link-freetext" href="https://www.reddit.com/r/java/comments/1nq25yr/critique_of_jep_505_structured_concurrency_fifth/" target="_blank">https://www.reddit.com/r/java/comments/1nq25yr/critique_of_jep_505_structured_concurrency_fifth/</a>), I’m writing here.</pre>
    </blockquote>
    Thanks for writing down your experiences.<br>
    <br>
    (I'll reply to your main points 1 and 2 later as they concern
    advanced use of the API that isn't straight-forward fan-out.)<br>
    <br>
    Just some quick comments on the two smaller points here:<br>
    <br>
    <br>
    <blockquote cite="mid:85467C61-8139-4832-B3BA-BFA53061E986@warski.org">
      <pre class="moz-quote-pre">3) The final two problems are more of nitpicks. First, a `timeout` method can easily be implemented using the machinery of the SCS, without additional configuration parameters. Special-casing for this seems odd, as timeout is only one example from a family of "resiliency" methods, others including retries, repeats etc. These as well, could be implemented on top of virtual threads and SCS as methods, without special support from the SCS API itself.</pre>
    </blockquote>
    If you implement your own Joiner with a side channel to this special
    timeout subtask then it would work. However in general, it will be
    policy (and hence Joiner) dependent as to whether a failing subtask
    will cancel the scope.  You'll see what I mean if you try with it a
    Joiner created by the anySuccessfulResultOrThrow factory method.
    Same thing with any Joiner that has a policy that doesn't
    unconditionally cancel when a subtask fails.<br>
    <br>
    Another point on this topic is that the timeout applies to the scope
    and configuring it when creating the scope is good. Additionally,
    having join throwing TimeoutException is useful to distinguish the
    timeout case from other failure outcomes.<br>
    <br>
    <br>
    <blockquote cite="mid:85467C61-8139-4832-B3BA-BFA53061E986@warski.org">
      <pre class="moz-quote-pre">4) The Subtask.get() method is confusing, as it has the semantics of Future.resultNow(), but the nomenclature of Future.get(). Since Future.get() is quite well established, I think it’s reasonable to assume, without prior knowledge of the SCS API, that Subtask.get() is blocking as well. However, it works rather differently. I understand that .get() is a fitting name, however given the existing functionalities in place, I would consider changing the name to something without naming or semantical clashes.
</pre>
    </blockquote>
    Subtask<T> is a Supplier<T>, and maybe more of the
    examples should use Supplier<T> to avoid anyone thinking
    Future::get. If someone does attempt to use Subtask::get before
    joining then it will throw of course, so they know to use it after
    join. Ron has long argued that fork should just return a Supplier,
    it's only use is when using subtasks return results of different
    types. If subtasks all return results of the same type then the
    outcome from join is much more useful, no need for Supplier::get.</blockquote><div><br></div><div>I think i agree with Ron, fork() should return a Supplier with get() failing if not called from the main thread.</div><div><br data-mce-bogus="1"></div><div>In that case, maybe Subtask.get() should not throw an exception when called from the main thread.</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br>
    <br>
    -Alan</blockquote><div><br></div><div>Rémi</div><div><br data-mce-bogus="1"></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><br><br></blockquote></div></div></body></html>