Hello all!
I would like to pitch changing how assignment statements which cross isolation domains work. As motivation, here's some code that compiles today:
@concurrent
func produceValue() async -> Int {
0
}
class AsyncTest {
var storage: Int = 5
subscript(index: Int) -> Int {
get { 0 }
set(newValue) { }
}
func performAssignment() async {
await self.storage = produceValue()
await self[0] = produceValue()
}
}
And here is some code that does not:
@MainActor
class IsolatedTest {
var storage: Int = 5
subscript(index: Int) -> Int {
get { 0 }
set(newValue) { }
}
nonisolated func performAssignment() async {
// ERROR: Main actor-isolated property 'storage' can not be mutated from a nonisolated context
await self.storage = produceValue()
// ERROR: Main actor-isolated subscript 'subscript(_:)' can not be mutated from a nonisolated context
await self[0] = produceValue()
}
}
This is an ergonomic issue. It is a common area of confusion. It is consistently difficult to explain to people getting started with the concurrency system. It's also something that frequently pushes people towards MainActor.run
. And while I think that construct does have its place, I don't think this is a great example of it.
I'd like to lift this restriction and permit this leading await
in these cases. I do want to point out that this is not about changing the nature of the properties themselves or touching on asynchronous setters.
I've begun writing a proposal for this, but it is still a very early draft:
I'd love to hear your feedback.