Different behaviour on adding explicit actor isolation to `group.addTask`

this is, i think, a fairly common misconception, but that is not what @isolated(any) does. the best discussion of this i've seen is here, and to quote a relevant bit:

without the explicit @SomeActor in the signature of the closures passed to group.addTask, those closures are not actor-isolated, so they begin execution on the global concurrent executor before switching to the custom executor for the actor-instance (hence the arbitrarily-ordered results).

as touched on here and here in that same thread, the intent of the taskGroup.addTask API specifically is to allow you to introduce concurrency between the parent and child tasks, so having those closures inferred to be isolated to their parent context by default would undermine the primary use case of the API.

one other thing that stood out to me in the example, which i imagine could also cause confusion, is that the SomeActor type is being used both as a global actor, and distinct instances are being created and used independently. in this construction, the shared instance and other instances do not share the same executor (each instance creates its own), so code running on one actor instance will not execute exclusively with code running on another (i think). additionally, the closure in code like this:

group.addTask {
    await instance.log(external: index)
}

is not isolated to the actor 'instance'. specifying that a closure be isolated to a specific actor instance is a feature that doesn't yet exist in the language.

3 Likes