Consider these giving structs:
//A struct with mutating async function
struct Model {
mutating func doSometingAsyncMutating() async {
//do something
}
mutating func doSomethingMutating() {
//do something
}
}
@MainActor
struct MyStruct {
var model: Model {
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async {
await model.doSometingAsyncMutating() //Error: Cannot call mutating async function 'doSometingAsyncMutating()' on actor-isolated property 'model'
}
mutating func callModelAsyncMutatingFunctionWithMutating() async {
await model.doSometingAsyncMutating() //ok
}
func callModelMutatingOnlyFunction() {
model.doSomethingMutating() // ok
}
}
As you can see, the setter of property model
is nonmutating
, but the function callModelAsyncMutatingFunction()
still throw the error Cannot call mutating async function 'doSometingAsyncMutating()' on actor-isolated property 'model'
, otherwise mutating function callModelFunctionWithMutating()
is ok.
And the funny thing is callModelMutatingOnlyFunction()
is ok, because it's not a async
function.
And if I remove the @MainActor
from MyStruct
, then all functions are ok:
// @MainActor
struct MyStruct {
var model: Model {
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async {
await model.doSometingAsyncMutating() //ok
}
mutating func callModelAsyncMutatingFunctionWithMutating() async {
await model.doSometingAsyncMutating() //ok
}
func callModelMutatingOnlyFunction() {
model.doSomethingMutating() // ok
}
}
My question is why the behaviour like that? It seems like there are many factors affecting one thing. And what I really try to achieve is like that:
@MainActor //I need @MainActor
struct MyStruct {
var model: Model { // Adding nonioslated not an option
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async { //Adding mutating not an option
await model.doSometingAsyncMutating() //I need it to be ok
}
}
I already checked a couple articles, like this, but not really helping, any idea?
Consider these giving structs:
//A struct with mutating async function
struct Model {
mutating func doSometingAsyncMutating() async {
//do something
}
mutating func doSomethingMutating() {
//do something
}
}
@MainActor
struct MyStruct {
var model: Model {
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async {
await model.doSometingAsyncMutating() //Error: Cannot call mutating async function 'doSometingAsyncMutating()' on actor-isolated property 'model'
}
mutating func callModelAsyncMutatingFunctionWithMutating() async {
await model.doSometingAsyncMutating() //ok
}
func callModelMutatingOnlyFunction() {
model.doSomethingMutating() // ok
}
}
As you can see, the setter of property model
is nonmutating
, but the function callModelAsyncMutatingFunction()
still throw the error Cannot call mutating async function 'doSometingAsyncMutating()' on actor-isolated property 'model'
, otherwise mutating function callModelFunctionWithMutating()
is ok.
And the funny thing is callModelMutatingOnlyFunction()
is ok, because it's not a async
function.
And if I remove the @MainActor
from MyStruct
, then all functions are ok:
// @MainActor
struct MyStruct {
var model: Model {
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async {
await model.doSometingAsyncMutating() //ok
}
mutating func callModelAsyncMutatingFunctionWithMutating() async {
await model.doSometingAsyncMutating() //ok
}
func callModelMutatingOnlyFunction() {
model.doSomethingMutating() // ok
}
}
My question is why the behaviour like that? It seems like there are many factors affecting one thing. And what I really try to achieve is like that:
@MainActor //I need @MainActor
struct MyStruct {
var model: Model { // Adding nonioslated not an option
get { /* some code */ }
nonmutating set { /* some code*/ }
}
func callModelAsyncMutatingFunction() async { //Adding mutating not an option
await model.doSometingAsyncMutating() //I need it to be ok
}
}
I already checked a couple articles, like this, but not really helping, any idea?
Share Improve this question edited Feb 15 at 16:45 matt 536k93 gold badges932 silver badges1.2k bronze badges asked Feb 15 at 8:39 TylerTyler 546 bronze badges 6 | Show 1 more comment1 Answer
Reset to default 0I believe you're overthinking this. The problem is that in
func callModelAsyncMutatingFunction() async {
await model.doSometingAsyncMutating() // *
}
... the term model
in the starred line is effectively a let
constant. Therefore it cannot be mutated. To mutate it, take a var
copy:
func callModelAsyncMutatingFunction() async {
var modelCopy = model
await modelCopy.doSometingAsyncMutating()
model = modelCopy // ?
}
You didn't explicitly say you wanted to set the mutated instance back into the self.model
so I've put a question mark next to that line. But I presume it is the sort of thing you want to do.
actor
s for this type of stuff. – lorem ipsum Commented Feb 15 at 8:48