StructureTaskScope joiner naming
David Alayachew
davidalayachew at gmail.com
Thu Sep 25 12:47:02 UTC 2025
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().
> "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.
Good point.
The name allUntil() leans heavily on the naming convention in order to make
sense, but reading it plainly definitely misleads you as to its actual
semantics.
Plus, I think your cancelWhen() suggestion is much clearer. Shame that it
must abandon the naming convention. At the end of the day, the naming
convention is useful, so I'd like any rename of this to maintain that
convention.
> 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"
This isn't a very strong argument, but at the same time, I think you have a
point.
There is significant value in having the default semantics be attached to
the name that users might first reach for.
That said, I think noCancellationVoidResult() is a very poor replacement
name.
Here is my attempt at it.
allSuccessful()
anySuccessful()
awaitAllSuccessful()
awaitAllDontThrow()
allUntil(Predicate)
I can appreciate that SC API designers trying to avoid the Optional.get()
fiasco by trying to use the xxxElseThrow and xxxOrThrow naming structure.
But Optional.get() was a fiasco because of WHERE Optional was being used --
aka, as a return type of basically ANY METHOD that can say "I may not
return anything!". Its UBIQUITY is what made Optional.get() a disaster --
get() implies many things in many contexts, so it was not a wise name to
use.
Joiner, in comparison, is a far more constrained domain. I think we can get
away with having throwing be the assumed default. After all, we have to
write a giant try-with-ressources anyways. I think the programmer is in the
frame of mind to expect Exceptions. And that's ignoring the fact that
join() throws! And that's even FURTHER ignoring the fact that, at use-site,
the developer is not calling get() when they want to join.
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?
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/448f20aa/attachment.htm>
More information about the loom-dev
mailing list