I'm struggling to understand how @isolated(any)
works in some cases.
var getString: @isolated(any) @Sendable () -> String
I understood (but correct me if I'm wrong) that this attribute tells that the function needs to be awaited since it's isolated to any actor and therefore I'd need to call it from an async function.
Now let's consider this example
struct Foo: Sendable {
var getString: @Sendable () -> String
init(getString: @escaping @Sendable () -> String) {
self.getString = getString
}
init(getStringIsolated: @isolated(any) @escaping @Sendable () -> String) {
getString = getStringIsolated
}
}
@MainActor
var globalString = "hello"
func test() {
let f1 = Foo(getString: {
// Main actor-isolated var 'globalString' can not be referenced from a nonisolated context
globalString
})
let f2 = Foo(getString: { @MainActor in // Converting function value of type '@MainActor @Sendable () -> String' to '@Sendable () -> String' loses global actor 'MainActor'
globalString
})
let f3 = Foo(getStringIsolated: { @MainActor in
globalString
})
let result = f3.getString() // OK
let f4 = Foo(getStringIsolated: {
"empty"
})
}
- Why in
f3
can I pass an isolated closure in theinit(getStringIsolated:)
even if the property is not isolated itself? - Why
f4
works even if I'm not isolating the function at all? does it mean that@isolated(any)
stands for "Any isolation or non-isolated at all" - Moreover if I change
getString
tovar getString: @isolated(any) @Sendable () -> String
, I can still have both initializers