<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>I have tried things out over the evolution of Structured
      Concurrency, but not this specific case.</p>
    <p>While I agree that trying things out is a <b><i>good </i></b>way
      to see how it works, trying things out does not confirm actual
      architectural or design intent, it merely speculates on intent. It
      would be nice for the architects to explicitly specify their
      intent in JEPs and elsewhere.</p>
    <p>But, thanks for the example... did you write it yourself, or have
      GitHub Copilot do it? ðŸ˜‰ Just teasing...<br>
    </p>
    <div class="moz-cite-prefix">On 2023-10-27 10:16 a.m., Josiah Noel
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAJ_t5UaOqKqjEZ=5sDPb24HNjAE+W4i4RnZ1CofcfJqmBhUc2w@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr">
        <div dir="ltr">
          <div dir="ltr">
            <div dir="ltr">
              <div dir="ltr">
                <div dir="ltr">
                  <div dir="ltr">Have you tried it out? Trying this
                    stuff out is the best way to see how it works, in
                    any case, observe the following example </div>
                  <div dir="ltr">
                    <div
style="background-color:rgb(28,31,34);padding:0px 0px 0px 2px">
                      <div
style="color:rgb(199,205,209);font-family:Consolas;white-space:pre"><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">   </span><span
                      style="color:rgb(255,0,127)">try</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(249,250,244)">(</span><span
style="color:rgb(82,227,246);background-color:rgb(65,65,4)">ShutdownOnSuccess</span><span
                      style="color:rgb(255,0,127)"><</span><span
                      style="color:rgb(191,164,164)">Integer</span><span
                      style="color:rgb(255,0,127)">></span><span
                      style="color:rgb(207,191,173)"> scope </span><span
                      style="color:rgb(255,0,127)">=</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(255,0,127)">new</span><span
                      style="color:rgb(207,191,173)"> </span><span
style="color:rgb(82,227,246);background-color:rgb(65,65,4)">StructuredTaskScope</span><span
style="color:rgb(255,0,127);background-color:rgb(65,65,4)">.</span><span
style="color:rgb(167,236,33);background-color:rgb(65,65,4)">ShutdownOnSuccess</span><span
                      style="color:rgb(255,0,127)"><></span><span
                      style="color:rgb(249,250,244)">())</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(249,250,244)">{</span></p><p
                      style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)">      </span><span
                      style="color:rgb(197,104,28)">var</span><span
                      style="color:rgb(207,191,173)"> fail </span><span
                      style="color:rgb(255,0,127)">=</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">          scope</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">fork</span><span
                      style="color:rgb(249,250,244)">(</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">              </span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(255,0,127)">-></span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(249,250,244)">{</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">                </span><span
                      style="color:rgb(255,0,127)">throw</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(255,0,127)">new</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(167,236,33)">IllegalAccessException</span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">              </span><span
                      style="color:rgb(249,250,244)">})</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)">      scope</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">fork</span><span
                      style="color:rgb(249,250,244)">(</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">          </span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(255,0,127)">-></span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(249,250,244)">{</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">            </span><span
                      style="color:rgb(82,227,246)">Thread</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">sleep</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(82,227,246)">Duration</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">of</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(207,191,173)">random</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">nextInt</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(196,140,255)">0</span><span
                      style="color:rgb(255,0,127)">,</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(196,140,255)">1000</span><span
                      style="color:rgb(249,250,244)">)</span><span
                      style="color:rgb(255,0,127)">,</span><span
                      style="color:rgb(207,191,173)"> ChronoUnit</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(207,191,173)">MILLIS</span><span
                      style="color:rgb(249,250,244)">))</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">            </span><span
                      style="color:rgb(255,0,127)">return</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(196,140,255)">1</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">          </span><span
                      style="color:rgb(249,250,244)">})</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)">      scope</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">fork</span><span
                      style="color:rgb(249,250,244)">(</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">          </span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(255,0,127)">-></span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(249,250,244)">{</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">            </span><span
                      style="color:rgb(82,227,246)">Thread</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">sleep</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(82,227,246)">Duration</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">of</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(207,191,173)">random</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">nextInt</span><span
                      style="color:rgb(249,250,244)">(</span><span
                      style="color:rgb(196,140,255)">0</span><span
                      style="color:rgb(255,0,127)">,</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(196,140,255)">1000</span><span
                      style="color:rgb(249,250,244)">)</span><span
                      style="color:rgb(255,0,127)">,</span><span
                      style="color:rgb(207,191,173)"> ChronoUnit</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(207,191,173)">MILLIS</span><span
                      style="color:rgb(249,250,244)">))</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">            </span><span
                      style="color:rgb(255,0,127)">return</span><span
                      style="color:rgb(207,191,173)"> </span><span
                      style="color:rgb(196,140,255)">2</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">          </span><span
                      style="color:rgb(249,250,244)">})</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px">
</p><p style="margin:0px"><span style="color:rgb(207,191,173)">      scope</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">join</span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">      </span><span
                      style="color:rgb(255,255,255)">// get first result, (will not care about exceptions as long as one succeeds)</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">      scope</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(167,236,33)">result</span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(255,0,127)">
</span></p><p style="margin:0px"><span style="color:rgb(207,191,173)">      </span><span
                      style="color:rgb(255,255,255)">// will throw an exception</span><span
                      style="color:rgb(255,0,127)">
</span></p><p style="margin:0px"><span style="color:rgb(207,191,173)">      </span><span
                      style="color:rgb(207,191,173)">fail</span><span
                      style="color:rgb(255,0,127)">.</span><span
                      style="color:rgb(190,214,255)">get</span><span
                      style="color:rgb(249,250,244)">()</span><span
                      style="color:rgb(255,0,127)">;</span></p><p
                      style="margin:0px"><span
                      style="color:rgb(207,191,173)">    </span><span
                      style="color:rgb(249,250,244)">}</span></p></div>
                    </div>
                  </div>
                  <div dir="ltr"><br>
                  </div>
                  <div dir="ltr"><br>
                  </div>
                  <div dir="ltr">Essentially, you must use the
                    `scope.result()` method to retrieve the result
                    instead of calling the get methods on a particular
                    subtask<input name="virtru-metadata" type="hidden"
value="{"email-policy":{"disableCopyPaste":false,"disablePrint":false,"disableForwarding":false,"enableNoauth":false,"expandedWatermarking":false,"expires":false,"sms":false,"expirationNum":1,"expirationUnit":"days","isManaged":false,"persistentProtection":false},"attachments":{},"compose-id":"1","compose-window":{"secure":false}}"></div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <br>
        <div class="gmail_quote" style="">
          <div dir="ltr" class="gmail_attr">On Fri, Oct 27, 2023 at
            12:37 PM Eric Kolotyluk <<a
              href="mailto:eric@kolotyluk.net" moz-do-not-send="true"
              class="moz-txt-link-freetext">eric@kolotyluk.net</a>>
            wrote:<br>
          </div>
          <blockquote class="gmail_quote"
style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
            <div>
              <p>Looks good... thanks.</p>
              <p>One slight area of confusion for me was, <br>
              </p>
              <pre><code><T> List<Future<T>> executeAll(List<Callable<T>> tasks)
        throws InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
          List<? extends Supplier<Future<T>>> futures = tasks.stream()
              .map(task -> asFuture(task))
              .map(scope::fork)
              .toList();
          scope.join();
          return futures.stream().map(Supplier::get).toList();
    }
}

static <T> Callable<Future<T>> asFuture(Callable<T> task) {
   return () -> {
       try {
           return CompletableFuture.completedFuture(task.call());
       } catch (Exception ex) {
           return CompletableFuture.failedFuture(ex);
       }
   };
}</code></pre>
              <p>And what happens if <code>ShutdownOnSuccess</code> is
                called instead. Eventually I reasoned that the right
                thing should happen, but there should only ever be one
                element in the list. Does the scope guarantee only one
                result?<br>
              </p>
              <ol>
                <li>It would be slightly helpful to point this out in a
                  note so that it is more obvious.</li>
                <li>What is less obvious is that with <code>ShutdownOnSuccess</code>
                  what happens if one or more of the siblings throw an
                  exception?</li>
                <ul>
                  <li>I would hope that so long at least one task
                    succeeds, this should not cause the overall success
                    of the scope to fail.</li>
                  <li>It would be nice to see this explained more
                    clearly.</li>
                  <li> Maybe <code>ShutdownOnSuccess</code> deserves its
                    own example, discussing possible edge cases.</li>
                </ul>
              </ol>
              <p>Somehow I am remembering Scala 'for comprehensions'
                with concurrent tasks that 'yield' a result... ðŸ˜‰</p>
              <p>The current situation seems kinda clunky with using one
                stream to collect futures, and yet another stream to
                collect results. Maybe one of the Java architects hates
                such boilerplate, and will come up with an elegant way
                to reduce/remove such boilerplate.<br>
              </p>
              <p>Sincerely, Eric<br>
              </p>
              <div>On 2023-10-27 7:39 a.m., Mark Reinhold wrote:<br>
              </div>
              <blockquote type="cite">
                <pre><a href="https://openjdk.org/jeps/462"
                target="_blank" moz-do-not-send="true"
                class="moz-txt-link-freetext">https://openjdk.org/jeps/462</a>

  Summary: Simplify concurrent programming by introducing an API for
  structured concurrency. Structured concurrency treats groups of related
  tasks running in different threads as a single unit of work, thereby
  streamlining error handling and cancellation, improving reliability,
  and enhancing observability. This is a preview API.

- Mark</pre>
              </blockquote>
            </div>
          </blockquote>
        </div>
      </div>
    </blockquote>
  </body>
</html>