<div dir="auto"><div>Whoops, minor modification.<div dir="auto"><br></div><div dir="auto">1. cancelWhen<BiPredicate<R, Subtask<T>>></div><br><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, Sep 25, 2025, 6:34 PM David Alayachew <<a href="mailto:davidalayachew@gmail.com">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div>Makes more sense.</div><div dir="auto"><br></div><div dir="auto">You could make a Joiner.Builder class with the following methods.</div><div dir="auto"><br></div><div dir="auto">1. cancelWhen(Predicate<Subtask<T>>)</div><div dir="auto">2. returnValue(R, BiConsumer<R, Subtask<T>>)</div><div dir="auto">3. throwWhen(Predicate<Subtask<T>>)</div><div dir="auto"><br></div><div dir="auto">And the absence of any of the above methods has the following default.</div><div dir="auto"><br></div><div dir="auto">1. Cancel on first Subtask Exception.</div><div dir="auto">2. Return all Subtasks as a List.</div><div dir="auto">3. Throw the first Subtask Exception.</div><div dir="auto"><br></div><div dir="auto">This gives you the power of permutation, while also give you the Pit of Success. Furthermore, you can do away with all of the static methods.</div><div dir="auto"><br></div><div dir="auto">The only weakness is that you leave performance on the table, in some cases. Plus, maintaining the Builder gets a little harder, but not by much.</div><div dir="auto"><br></div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Thu, Sep 25, 2025, 4:58 PM <<a href="mailto:forax@univ-mlv.fr" target="_blank" rel="noreferrer">forax@univ-mlv.fr</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div style="font-family:arial,helvetica,sans-serif;font-size:12pt;color:#000000"><div><br></div><div><br></div><hr id="m_-8936623248114507798m_4133179810143448211zwchr"><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"><b>From: </b>"David Alayachew" <<a href="mailto:davidalayachew@gmail.com" rel="noreferrer noreferrer" target="_blank">davidalayachew@gmail.com</a>><br><b>To: </b>"Remi Forax" <<a href="mailto:forax@univ-mlv.fr" rel="noreferrer noreferrer" target="_blank">forax@univ-mlv.fr</a>><br><b>Cc: </b>"loom-dev" <<a href="mailto:loom-dev@openjdk.java.net" rel="noreferrer noreferrer" target="_blank">loom-dev@openjdk.java.net</a>><br><b>Sent: </b>Thursday, September 25, 2025 2:47:02 PM<br><b>Subject: </b>Re: StructureTaskScope joiner naming<br></blockquote></div><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"><div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello Rémi,<br><br>> TS.join() always wait, so this is <br>> confusing because a joiner with a <br>> name that does not start with the <br>> name "await" still await.<br><br>The method name join() makes perfect sense to me -- it joins all the threads.<br><br>And more accurately, it isn't just waiting, it is joining! Remember that STS with the default semantics (STS.open()) are those that it would have if we did CompletableFuture.allOf().join().<br><br>Therefore, to base your name off of waiting instead of joining would be the wrong semantics. The method name should remain as join() and should not be called anything else. Especially not await().</div></div></blockquote><div><br></div><div>I think you misunderstood me,</div><div>i was criticizing the name of the joiners, not the name of STS.join().</div><div><br></div><div>Some joiners starts with the prefix "await", some don't, but they all wait, because waiting is something done by the STS implementation, not by the joiner implementation.</div><div><br></div><div>[...]</div><div><br></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"><div dir="ltr"><div class="gmail_default" style="font-family:monospace"><br><br>How do you feel about my naming suggestions instead Rémi? I don't have a good replacement for allUntil's name, and I don't want to use cancelWhen, since it throws out the naming convention. But otherwise, how do you feel about it?</div></div></blockquote><div><br></div><div>I obviously prefer mine :)</div><div>i.e, I think "all" and "await" should not be parts of the name, "await" as discussed above and "all" because the fact that you want all the subtaks whatever their states is a separated concern. </div><div><br></div><div>Rémi</div><div><br></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><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Sep 25, 2025 at 2:20 AM Remi Forax <<a href="mailto:forax@univ-mlv.fr" rel="noreferrer noreferrer" target="_blank">forax@univ-mlv.fr</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">So currently we have those joiner defined in the JDK:<br>
- allSucessfulOrThrow()<br>
- anySucessfulResultOrThrow()<br>
- awaitSucessfulOrThrow()<br>
- awaitAll()<br>
- allUntil(predicate)<br>
<br>
There are several issues,<br>
- TS.join() always wait, so this is confusing because a joiner with a name that does not start with the name "await" still await.<br>
If you take a look to the doc, the prefix "await" seems to be used to convey the idea that the result of the STS.join() is null,<br>
i.e the joiner does not stores the forked subtasks in a list. <br>
<br>
- The other issue is the naming of awaitAll(), which is the shorter name, so people will be droven to use it by default, "it's the simpler",<br>
but unlike the other joiners, it does not cancel the other subtasks in case of failure, which is not the semantics you want by default.<br>
The name seems to imply that because it does ends with "OrThrow", it means that there is no cancellation.<br>
<br>
- "allUntil" is a half-lie, it will correctly cancel the other subtask when one task validates the predicate but at the same time,<br>
STS.join() will returns all subtasks, not the ones until the predicate is true.<br>
The name "allUntil" only make sense if you see it as the concatenation of two orthogonal behaviors, "all" meaning STS.join() returns<br>
all subtasks and "until" meaning stop when the predicate is true.<br>
<br>
I propose this renaming (in order):<br>
- allSuccessful()<br>
- anySuccessful()<br>
- sucessfulVoidResult()<br>
- noCancellationVoidResult()<br>
- cancelWhen(predicate)<br>
<br>
After that, i think we can be a little more fancy and see the fact that the implementation returns all subtasks as a separate concern,<br>
thus enable composition:<br>
- sucessful().all()<br>
- anySucessful()<br>
- sucessful()<br>
- nonCancellation()<br>
- cancelWhen(predicate).all()<br>
<br>
With all() a default method that override onFork() and result() to respectively add each subtask in a list and blindly returns that list.<br>
<br>
regards,<br>
Rémi<br>
<br>
<br>
<br>
<br>
<br>
</blockquote></div><br></blockquote></div></div></div></blockquote></div></div></div>
</blockquote></div></div></div>