First off, apologies if this question has already been answered elsewhere. I'm still new to Swift Concurrency, and I don't think I have all the proper vocabulary figured out yet, which makes searching difficult.
Say that I have a protocol, and I pass an instance of that protocol into a function:
protocol MyProtocol {
func doSomething()
}
func myFunction(myParam: MyProtocol) {
myParam.doSomething()
}
However, I have two different implementations of MyProtocol
: one that is non-isolated, and one that is isolated to the MainActor
:
class MyRegularImpl: MyProtocol {
func doSomething() {}
}
@MainActor
class MyMainActorImpl: MyProtocol {
func doSomething() {}
}
Obviously in the MainActor
version I get a warning that the isolated version of doSomething()
can't be used to satisfy the protocol. However, I think it is actually "safe" because I only ever call myFunction()
with MyMainActorImpl
the from the MainActor
. Also I don't hold onto the passed-in instance - it is only used within the scope of the function call. And I don't send it across any isolation boundaries.
Is there any way to express this restriction / nuance using Swift Concurrency? Or is there some different approach I should be considering?
Complicating Factors:
- These functions need to stay synchronous. Unfortunately I can't just change them to be async at this time.
- I think maybe you can express this somehow if the non-isolated version was instead also isolated to some actor. But unfortunately I can't do that either.
- Ideally I would be able to stay in Swift 5 language mode. But upgrading to 6 might be possible if this provided a good solution. Would SE-0446 "non-escapable types" help with this?
- In my real code, the function provided by
MyProtocol
is generic. In some other instances, I was able to get around this isolation problem by wrapping the call todoSomething()
in a closure, and then passing in the closure instead of the protocol instance. This seemed to work fine, I guess since the closure parameter was non-escaping? But unfortunately closures can't be generic.