Suppose you have a family of classes that you want to be isolated to one specific actor.
You'd probably declare a "faux" global actor:
@globalActor
actor MyActor {
static var shared = MyActor() // not used explicitly
}
and then use @MyActor whenever you need to declare isolation to it.
Firstly, I'm not sure this is the best pattern for this kind of situations. And second: if it is, I'm left with MyActor.shared that shouldn't be used directly, which feels a bit off.
What am I doing wrong? Or can this pattern be somehow improved?
Is that the case? As in: I didn't know that (yet), though that does not mean I have ever had the need to use it.
I guess the concurrency runtime itself surely needs exactly one instance of the actor to do its work (which is to ensure that everything annotated accordingly only runs in this actor's isolation context).
My guess is that it uses that shared instance by definition.
Otherwise it would have to instantiate one itself, but if you marked the initializer as private or have some complicated logic needed to create it, how would it do that? There needs to be some kind of protocol for that, and imo a shared instance makes the most sense.
This instance would probably also be passed to isolated parameters, then you could use === to see if it's "your actor". Not that I'd have a use case handy for that, but that would be an explicit use of the property.
Have I perhaps not yet read some documentation that warns you to use the shared instance in some other way?
A global actor is a type that has the @globalActor attribute and contains a static property named sharedthat provides a shared instance of an actor. For example:
[…]
A global actor type can be a struct, enum, actor, or final class. It is essentially just a marker type that provides access to the actual shared actor instance via shared.[emphasis mine — vns] The shared instance is a globally-unique actor instance that becomes synonymous with the global actor type, and will be used for synchronizing access to any code or data that is annotated with the global actor.
Global actors implicitly conform to the GlobalActor protocol, which describes the shared requirement.[emphasis mine — vns] The conformance of a @globalActortype to the GlobalActor protocol must occur in the same source file as the type definition, and the conformance itself cannot be conditional.
Basically, you simply conform to a protocol to define a global actor — just in a bit unusual for Swift way.
@bbrk24 gave one example of how you may want to use that, but I think other scenarios are also possible.
Nowhere in the proposal does it say that you should not use the static instance somewhere.
Of course I am aware that was not all you said!
I just wanted to point out that you can use it in different ways, too (for example in a same-reference check).
I guess the "feeling off" is a matter of opinion. I understand where you're coming from, but personally don't see it in that light. For me it's a little like a typealias that defines an associated type when adopting a protocol. Actually, it's even more just like adopting a protocol.
What could be seen as weird, now that I think about it, is that the "thing" that relies on the conformance is "the concurrency runtime", in a very opaque manner. We don't directly see the API that requires this static property, but it makes sense that it is there.
Oh, and the @globalActor annotation, to me, was immediately clear from the get-go as a "this is just so you can have your own annotation elsewhere", something that, unlike the concurrency runtime requiring a specific thing, is not expressible by the normal type system.