On Tue, Mar 24, 2026 at 5:32 PM Alan Bateman <[email protected]>
wrote:

> > 2. StructuredTaskScope seems like a long name
>
> We've been around and around this many times.


This kind of complaint is easy to dismiss as just bikeshedding. Naming
things is hard and at a certain point one needs to move on.

However, I don't think history will be kind with the naming of this API. It
smells peak expert's curse, it's a bottom-up name, named from the point of
view of an implementer, keen to demonstrate everything that's new and shiny
and different from the past. It's not sympathetic to new users, instead
rather scary and off-putting. It's weirdly too abstract and too concrete at
the same time. It tries to say too much but ends up communicating very
little.

The "Scope"-ness of STS is a linguistic structure, this is not begging for
a name. It's as-if we named InputStream "InputStreamScope" just because
try-with-resources cleans it up at the end of the block.

The "Structure" is also redundant, more like a marketing term label: "hey,
look here, we're structured!". The structure is the shape of
task composition provided by the programmer, the API just enables this
structure. The code is the structure, not the API. This does not beg for a
name.

"Subtask" is a decomposition of a task, but the task API is nowhere to be
found. This looks strange to me.

The "Joiner" is weakly named, maybe because it has too many
responsibilities. No pointy-haired boss ever uttered: "Fred, will your
tasks be joined by Friday?". In the real world, tasks are completed, not
joined. Worse, we don't even join a task, we join a scope: scope.join().
Joining a scope makes no sense.

Also, "fork" probably borrows from Fork/Join or OS process forking. But
leaning too much on the past often adds more confusion than clarity. I
still don't see why we need to fork tasks instead of just defining them. If
we didn't fork, then we would not need to "join". We could just let the
user compose tasks into subtask and defer execution until the user requests
completion. WIth the current model, the composition and execution phases
are not cleanly separated so the state is more tricky to reason about than
need be. It also leads to the joiner needing to be specified at task
opening, while any "definition of done" for a complete operation should
rather be passed as an argument to that operation.

A better name has not emerged and we've grown to live with the current name
> (and location).
>

It seems the name just got normalized. The fact that we've grown to live
with it will not help future Java programmers trying to learn and teach
this API.

What the API provides is a way to decompose a task into subtasks, associate
them with a lingusting scope, define what it means for the task as a whole
to be done and clean up subtasks before exiting the scope. The rest is
details :-)

As an API user who just wants my tasks to be done by Friday, I'd be happy
with just "Task":

try (var task = Task.open()) {
    Subtask<String> subtask = task.subtask(() -> {
        return fetchFromA();
    });
    scope.complete(allSuccessfulOrThrow());
    return subtask.get();
}

Cheers,
Eirik.

Reply via email to