The reason why isolating a non-Sendable
type to an actor instance dynamically is different and more complicated than global actor isolation is because it is inherently value dependent. To support isolating an entire non-Sendable
type to a specific actor instance, we need some form of value dependent types in order to know statically that calls do not cross an isolation boundary, or you need to work with the non-Sendable
value as if the isolated actor value is completely opaque, meaning you always need to interact with it asynchronously. Interacting with the non-Sendable
value asynchronously is fine for your use case here, but it's not for many of the other use cases involving non-Sendable
types that folks are struggling with. In any case, the discussions around the idea to isolated entire non-Sendable
types to actor values is happening in Isolation Assumptions.
I'm not suggesting making every type into an actor, but as soon as you start trying to parallelize work over non-Sendable
types, you're going to run into problems because data isolation requires the values used in those separate tasks to be Sendable
. Using an actor directly is one common way to turn a bag of mutable state into something that is Sendable
that you can use inside two different tasks that run on the global concurrent pool in parallel. Isolating the type to something else, be that a global actor or a specific actor value, is another way to turn a bag of mutable state into something that is Sendable
.