Let me say upfront that I do not feel qualified enough to be commenting on changes in the language. But I've had to explain Concurrency to other developers before, so I wanted to join the numerous other posts on the naming of @concurrent
.
I feel like there already is some asymmetry when stating isolation in functions and closures. Here are some examples:
nonisolated // only for functions
@isolated(any) // only for closures
@GlobalActor // for functions and closures
isolated SomeActor // for functions and closures
// and now:
@concurrent // only for functions
I think symmetry would let developers get to know isolation control in a more structured way. Talking about (self) teaching but also a great opportunity for documentation. (I am mentioning documentation because I could not find an official document, other than maybe the Swift 6 migration guide and proposals, talking about nonisolated
or isolated(any)
).
Now, what do I mean by symmetry. I am pretty sure, someone else mentioned a similar way of writing this in this thread already, but I feel like @isolated(global)
or something along those lines could be a great start instead of @concurrent
. Why? Let's assume in a future proposal, we could formalize isolation symmetry like this:
// A new annotation, that, after this proposal gets accepted,
// is the default annotation of every non-isolated async and sync function.
// Therefore it does not have to written out by the programmer, but could be,
// if you want to have more clarity and resilience against future changes in isolation control.
// This annotation of course infers `nonisolated`.
@isolated(caller) func test() { }
// Currently proposed as `@concurrent`, only available for asynchronous functions,
// but could be expanded to be used in synchronous functions as well.
// It states that the isolation should be chosen by the cooperative global executor.
// This annotation also infers `nonisolated`.
@isolated(global) func test() async { }
// A new annotation which is the longer form of @GlobalActor.
// Both ways to write global actor isolation should be allowed.
// This is the default annotation for isolated async and sync functions.
// For structs and classes isolated to actors or actors themselves,
// those annotations are inferred, but could again be written out.
@isolated(MainActor) func test() { }
@isolated(Self) func test() { }
// I could not find a symmetrical way to express functions that are isolated to actor instances.
// So I guess it has to stay like this:
func test(actor: isolated SomeActor) { }
Symmetry to closures:
func test(closure: @isolated(caller) () -> Void) { }
func test(closure: @isolated(global) () async -> Void) { }
func test(closure: @isolated(MainActor) () -> Void) { }
func test(closure: (isolated SomeActor) -> Void) { }
// There is one annotation that only makes sense for closures,
// but conveniently, it is spelled similarly:
func test(closure: @isolated(any) () -> Void) { }
// The behavior of `@isolated(any)` would of course stay the same.
// It gets its isolation dynamically from the closure itself.
These changes should also be purely additional. So the developer could stick to their preferred isolation annotation.
Don't get me wrong I do not want to hijack this pitch, nor am I pitching the syntax I sketched out, but I am trying to make the point that the writing of @concurrent
might be a missed chance to get uniform isolation annotations in the future and also it is another keyword to remember instead of a "keyword family".
If I got something wrong and this is just not possible at all, then please correct me and ignore the alternative writing I propose. This all is still somewhat new and keeping up with all proposals and understanding them is some work.