Protocol based Actor vs Specific Actor access with and without suspension

Hi.

Can somebody help me figure out what is going on behind this code. I extracted it to minimum. When I declare actorHolder as ActorHolder protocol then to access internal actor property I need to use await and create suspension point. But when I declare it as specific actor MyActorHolder then I don't need to create suspension points accessing internal property. Take a look:

actor MyActor {}

protocol ActorHolder: Actor {
    var actor: MyActor { get }
}

actor MyActorHolder: ActorHolder {
    let actor = MyActor()
}

actor MyClassWithActorHolderDeclaredAsProtocol {
    var actorHolder: ActorHolder = MyActorHolder() // <- Protocol based declaration

    func myFunc() async {
        let actor = await actorHolder.actor // Here I need to suspend (add await)
    }
}

actor MyClassWithActorHolderDeclaredAsSpecificActor {
    var actorHolder: MyActorHolder = MyActorHolder() // <- Specific actor declaration

    func myFunc() {
        let actor = actorHolder.actor // <- Here I don't need to suspend
    }
}

So the quesion is why in one case myFunc need to be declared asynchronous and in other case can be declared without async keyword because in those other case I'm not forced to use suspension point to access to the internal property. I know that function that can be suspended need to be declared as async but why in one case I need to suspend and in other case not?

I was expecting that myFunc is executed in actor Domain context so in the domain of MyClassWithActorHolderDeclaredAsSpecificActor or MyClassWithActorHolderDeclaredAsProtocol and to access property in other actor I need to switch domains so I need to use await there. And my assumption is right but only for the Protocol bases declaration of actorHolder

Anyone can put more light on this? I'm a little bit confused and maybe I will learn something useful from this.

1 Like