SE-0304: Structured Concurrency

Continuing on API notes then... commenting here on behalf of myself, so others or the core team may disagree – we'll see :slight_smile:

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:


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 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 :wink: 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.


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.


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?) :wink:

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.

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


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.


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


Hah yes, there was a PR and was reverted... :slight_smile: 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.

3 Likes