Continuing on API notes then... commenting here on behalf of myself, so others or the core team may disagree – we'll see
I hear you loud and clear on this one. It's really too bad that async let
and anything with "nicer to look at syntax" was decided to be punted out of this proposal and into a future one; as really the groups API here is really not what most people will be interacting with at all on a daily basis, unless building your own concurrency "operator" like a scatter-gather or "race" or similar.
So I feel a bit "hands tied" on that – as we said we'll leave the nice syntax and niceties to a future proposal, but let's go through one by one:

Near as I can tell,
Task
wears multiple hats:
- It is a namespace for task-related functions that might otherwise be global functions (and indeed, the
Task.with*Continuation
functions were split out from this proposal and actually made global functions).
Right, yes those did become top level, though mostly due to a lot of prior art with the various withUnsafe...
functions that already exist and these fitting the same style. Nor are they really about Task
(much less than all the other ones in this proposal).

I would strongly suggest jettisoning the use of
Task
as a namespace, and as much as possible to find a principled way to deduplicate static and instance methods that serve the sample purpose.
I feel this one really boils down to personal style and opinions a lot... As a person I do like the Task
namespace a lot, but I'm just one of the authors and by far not the one with most influence on it I'll leave that up to the core team to decide as it's a general Swift library style guideline thing.
The reason the namespace is nice is because it's easy to discover similar APIs I might need - e.g. this way I might learn about Task.local
etc.

UnsafeCurrentTask
Elsewhere, Swift provides
with*
APIs to expose something that shouldn’t be stored and “used later.” Was such a design considered instead ofunsafeCurrent
? Is there some consideration which prevents such a design here?

Could we use an "
withUnsafelyDeterminingTask<R>(do body: (UnsafeCurrentTask?) throws -> R) rethrows -> R?
" function?
I don't think there's any technical reason other than "yet again more nesting".
Usages of this are likely to be deep in framework and library code so it may not be a "huge" issue.
We had hoped to have @unmovable
at some point during the initial drafts... which would disallow escaping/moving the value out of the current scope, meaning that the closure would not really be necessary.
I'll leave that to @John_McCall or @Douglas_Gregor to comment if that's a likely future direction or not.

it does not make sense to me to try to pessimize the naming of a type.
To preserve the intention of futures taking a backseat in this design, there are other tools in the API design toolbox; we can look, for example, to the precedent of
Result
deliberately vending a limited API for the purposes that it's meant to serve while making clear that it's not meant to be an alternative to supplant throwing functions.
I'm not sure I agree with this; It is not only "pessimizing" the name, but also setting expectations correctly: Looking at this as a "language immigrant", coming from another language (e.g. Scala, Ruby, JS, Java, Kotlin...), or even just Swift with pervasive PromiseKit, NIO or Combine's Future types seeing a Future
in Swift would trigger the "I know how to use this, map(), flatMap(), right?" and then disappointment (and maybe finally enlightenment?)
I think it is useful to call this a Task.Handle
because it will not lead people into cargo culting on "okey, instead of NIO Future we pass now Swift Future" but rather lead into rethinking things a little bit more -- one would hope.

For the same reason, I think the primitive
Task.runDetached
(as have thought others here on the forums) can have a more succinct name also. Yes, it is a primitive that we're not trying to put forward as the go-to option in concurrency (pun intended). But neither does that mean that we need to namespace and pessimize the naming of it. It would seem to me that a global function merely namedrun
,detach
,spawn
,launch
, or anything similar would work. If we're worried that structured concurrency facilities can't compete with that sort of name, then we should optimize the design of the rest of the facilities, not pessimize this one.
Maybe there's a middle ground here?
I–personally–would for example like if we took two verbs and hyper focused on using them throughout the APIs, e.g.: group.spawn (child task)
and Task.detach
and if any other forms of child tasks were allowed to be spawned we'd also talk about them using spawn
. If any other "not child" tasks were allowed to be spawned, we'd use the verb "detach".
I would definitely not want to use Task.launch
or Task.new
as the detach
operation. It looks too inconspicuous but is actually a disaster for priority and tracing propagation. So it has to "shout" that "I am going to abandon all information from my parent task!!!"

This isn't the relationship being described here: a
Group
isn't a kind ofTask
, and while it's true that aTask
can have manyGroup
s, the much more salient point we're emphasizing here (the "structure" in structured concurrency) is that aGroup
is something that has manyTask
s.
As I said before, this really feels like an opinion / personal preference thing to be honest, so let's see what the core team comes up with. Yeah it could be either Task.Group
or TaskGroup
doesn't really matter.
I will say however that there definitely will be new "concurrency container thingy" types in the future. So whatever we do here affects future APIs like Task.DetachedLifecycleAttachedToClassContainer
or similar types.

By default, the task group will schedule child tasks added to the group on the default global concurrent executor. The startingChildTasksOn argument can be provided to override this behavior.
Why does this API need to differ from the preceding API in the text, clarifying that it’s child tasks that are started on an executor, rather than just spelling the argument label just
startingOn
? Can anything but a task be scheduled on an executor, and could the task group be scheduling anything but its child tasks?
I believe Joe's idea here was to spell out that it is not the group that will run on any other executor, which the following spelling might imply to the reader: withGroup(startingOn: coolExecutor)
vs. the boringly explicit withGroup(startingChildTasksOn: coolExecutor)
. We had a number of people be confused if the group itself is a task or not etc. (in fact, it used to be a child task, but isn't anymore).

The add operation returns true to indicate that the task was added to the group, and false otherwise. The only circumstance under which the task will not be added to the group is when the task group has been cancelled; see the section on task group cancellation for more information.
What is the rationale for returning
true
orfalse
(an unusual way to signal failure in Swift) versus, say, not returning a value but throwingCancellationError
?
The actual proper solution IMHO would be soft-faults here...
I've been hoping for those for a long long time already: [stdlib] Cleanup callback for fatal Swift errors - #4 by ktoso
The lack of panics or similar mechanisms in Swift and the very explicit nature of Errors
forces us into these weird API decisions... Specifically this is about: It is not the operation that might "fail", it is the infrastructure that might. The same appears in networking, or other panics vs errors situations...
But we're not going to get panics / soft faults any time soon I guess. So this design is being forced to think about -- is this automatic cancellation case worth the syntactic noise of having to try
every single group.add
even though the vast majority of time those will never throw...?

Longstanding convention in U.S. English, and specifically observed in past Apple style guides, is that the word is spelled "canceled" with one "l" (while "cancellation" is always spelled with two).
I understand there was some attempt to implement this in the APIs here, but it was reverted pending further discussion on review.
Hah yes, there was a PR and was reverted... There seems to be both prior art for disregarding the language rules in Apple APIs e.g. NSOperation (regardless of it being wrong linguistically...). Also some people expressed that they feel super strongly about it, so indeed the current and expected spelling is cancel, cancelled, cancellation - as weird as it it.