StructureTaskScope joiner naming
David Alayachew
davidalayachew at gmail.com
Thu Sep 25 22:38:22 UTC 2025
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/20250925/d649c747/attachment.htm>
More information about the loom-dev
mailing list