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 >>> >>> >>> >>> >>> >>> >>
