I'll fix the proposal. It should look like this:
@globalActor
public struct SomeGlobalActor {
public actor MyActor { }
public static let shared = MyActor()
}
MyGlobalActor is providing the type identity for the global actor. There's an underlying actor instance that handles the coordination, which is accessed via shared.
Hmm, I wonder what this would look like. nonisolated disables the implicit propagation of actor isolation, whether from an actor type or a global actor.
This would be different from the other kinds of custom attributes (property wrappers, result builders), so I think we'd need to convince ourselves that something like @MainActor is insufficiently clear to both deviate from other custom attributes and make its use significantly longer.
To me it looks like it's parameterizing the attribute, not the whole declaration. Are the generic requirements of the @isolated required to exactly match those of T? If there is a where clause, where does it go?
This issue of referencing generic parameters before they are declared (but in the same declaration) isn't totally new. We do it with the underscored @_specialize attribute:
@_specialize(exported: true, where T==UInt)
func increment<T: BinaryInteger>(_ t: T) -> T {
let incremented = t + 1
return incremented
}
Let's say I had to put both a global actor and an @_specialize on a declaration. Would I have to declare T three times now, and all consistently? I don't think this syntax scales, and I don't think it's clearer.
Yes, it's effectively this:
let callbackAsynchly: (Int) async -> Void = {
await callback() // `await` is required because callback is `@MainActor`
}
An actor "hop" is a no-op if you're already running on that actor.
Yes, that's correct. Global-actor-ness isn't inherited, either, so you could have a @globalActor superclass and then use one of its subclasses as an attribute.
Default implementations aren't really a construct in the language. They're declarations in a protocol that can be used to witness a requirement if there is no better option. So. they don't infer isolation.
Hmm. I don't think it's technically impossible to implement this, but it's a lot of extensions: we don't permit overloading of accessors today, nor do we permit overloading based on the global actor.
It's a bug in the example. I've fixed it in the proposal (see above).
@anandabits provided some rationale here. Global actors let you pull in declarations from all of your program to synchronize on a single actor, which you can't do with actor types.
Doug