StructureTaskScope joiner naming
Paul Bjorkstrand
paul.bjorkstrand at gmail.com
Fri Sep 26 14:37:42 UTC 2025
Maybe a page can be taken from JS Promise static methods [1]:
* Joiner.all() instead of Joiner.allSuccessfulOrThrow()
* Joiner.allSettled() instead of Joiner.awaitAll()
* Joiner.any() instead of Joiner.anySuccessfulResultOrThrow()
* Joiner.until(..) instead of Joiner.allUntil(..) [not part of the JS
Promise static functions, but seemed like a logical extension to the naming
pattern]
As a side note, perhaps having Joiner.allSettled() return the subtasks
themselves (in a stream?), and you can interrogate each one for
success/failure, rather than having to manually keep track of subtasks for
later use.
// Paul
[1]:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#static_methods
On Thu, Sep 25, 2025 at 5:38 PM David Alayachew <davidalayachew at gmail.com>
wrote:
> Lol, and maybe this too.
>
> 3. throwWhen(BiPredicate<R, Subtask<T>>)
>
> On Thu, Sep 25, 2025, 6:36 PM David Alayachew <davidalayachew at gmail.com>
> wrote:
>
>> Whoops, minor modification.
>>
>> 1. cancelWhen<BiPredicate<R, Subtask<T>>>
>>
>>
>> On Thu, Sep 25, 2025, 6:34 PM David Alayachew <davidalayachew at gmail.com>
>> wrote:
>>
>>> Makes more sense.
>>>
>>> You could make a Joiner.Builder class with the following methods.
>>>
>>> 1. cancelWhen(Predicate<Subtask<T>>)
>>> 2. returnValue(R, BiConsumer<R, Subtask<T>>)
>>> 3. throwWhen(Predicate<Subtask<T>>)
>>>
>>> And the absence of any of the above methods has the following default.
>>>
>>> 1. Cancel on first Subtask Exception.
>>> 2. Return all Subtasks as a List.
>>> 3. Throw the first Subtask Exception.
>>>
>>> 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.
>>>
>>> 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.
>>>
>>>
>>> On Thu, Sep 25, 2025, 4:58 PM <forax at univ-mlv.fr> wrote:
>>>
>>>>
>>>>
>>>> ------------------------------
>>>>
>>>> *From: *"David Alayachew" <davidalayachew at gmail.com>
>>>> *To: *"Remi Forax" <forax at univ-mlv.fr>
>>>> *Cc: *"loom-dev" <loom-dev at openjdk.java.net>
>>>> *Sent: *Thursday, September 25, 2025 2:47:02 PM
>>>> *Subject: *Re: StructureTaskScope joiner naming
>>>>
>>>> Hello Rémi,
>>>>
>>>> > TS.join() always wait, so this is
>>>> > confusing because a joiner with a
>>>> > name that does not start with the
>>>> > name "await" still await.
>>>>
>>>> The method name join() makes perfect sense to me -- it joins all the
>>>> threads.
>>>>
>>>> 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().
>>>>
>>>> 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().
>>>>
>>>>
>>>> I think you misunderstood me,
>>>> i was criticizing the name of the joiners, not the name of STS.join().
>>>>
>>>> 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.
>>>>
>>>> [...]
>>>>
>>>>
>>>>
>>>> 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?
>>>>
>>>>
>>>> I obviously prefer mine :)
>>>> 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.
>>>>
>>>> Rémi
>>>>
>>>>
>>>> On Thu, Sep 25, 2025 at 2:20 AM Remi Forax <forax at univ-mlv.fr> wrote:
>>>>
>>>>> So currently we have those joiner defined in the JDK:
>>>>> - allSucessfulOrThrow()
>>>>> - anySucessfulResultOrThrow()
>>>>> - awaitSucessfulOrThrow()
>>>>> - awaitAll()
>>>>> - allUntil(predicate)
>>>>>
>>>>> There are several issues,
>>>>> - TS.join() always wait, so this is confusing because a joiner with a
>>>>> name that does not start with the name "await" still await.
>>>>> 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,
>>>>> i.e the joiner does not stores the forked subtasks in a list.
>>>>>
>>>>> - 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",
>>>>> 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.
>>>>> The name seems to imply that because it does ends with "OrThrow", it
>>>>> means that there is no cancellation.
>>>>>
>>>>> - "allUntil" is a half-lie, it will correctly cancel the other subtask
>>>>> when one task validates the predicate but at the same time,
>>>>> STS.join() will returns all subtasks, not the ones until the
>>>>> predicate is true.
>>>>> The name "allUntil" only make sense if you see it as the
>>>>> concatenation of two orthogonal behaviors, "all" meaning STS.join() returns
>>>>> all subtasks and "until" meaning stop when the predicate is true.
>>>>>
>>>>> I propose this renaming (in order):
>>>>> - allSuccessful()
>>>>> - anySuccessful()
>>>>> - sucessfulVoidResult()
>>>>> - noCancellationVoidResult()
>>>>> - cancelWhen(predicate)
>>>>>
>>>>> 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,
>>>>> thus enable composition:
>>>>> - sucessful().all()
>>>>> - anySucessful()
>>>>> - sucessful()
>>>>> - nonCancellation()
>>>>> - cancelWhen(predicate).all()
>>>>>
>>>>> With all() a default method that override onFork() and result() to
>>>>> respectively add each subtask in a list and blindly returns that list.
>>>>>
>>>>> regards,
>>>>> Rémi
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250926/04c2a762/attachment.htm>
More information about the loom-dev
mailing list