Lol, and maybe this too. 3. throwWhen(BiPredicate<R, Subtask<T>>)
On Thu, Sep 25, 2025, 6:36 PM David Alayachew <[email protected]> wrote: > Whoops, minor modification. > > 1. cancelWhen<BiPredicate<R, Subtask<T>>> > > > On Thu, Sep 25, 2025, 6:34 PM David Alayachew <[email protected]> > 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 <[email protected]> wrote: >> >>> >>> >>> ------------------------------ >>> >>> *From: *"David Alayachew" <[email protected]> >>> *To: *"Remi Forax" <[email protected]> >>> *Cc: *"loom-dev" <[email protected]> >>> *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 <[email protected]> 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 >>>> >>>> >>>> >>>> >>>> >>>> >>>
