Why can't I set properties asynchronously?

Given:

@MainActor
class UserSettings {
    var isFeatureEnabled = false
}

It is really incongruous to me that, given the code above, I can get the value of isFeatureEnabled from a non-main-actor context, but I cannot set the value:

// fine:
let isFeatureEnabled = await settings.isFeatureEnabled

// very not fine:
await settings.isFeatureEnabled = true

There are three main ways to work around this:

:one: Make a method

extension UserSettings {
    func setIsFeatureEnabled(_ bool: Bool) { self.isFeatureEnabled = bool }
}

This feels like unnecessary ceremony and is prone to typographical naming errors and leads to inconsistencies in that sometimes I can do .isFeatureEnabled = value and sometimes I must use the method.

:two: Directly await the MainActor:

await MainActor.run { settings.isFeatureEnabled = true }

This requires me to know that the settings type is @MainActor, even though the type is already decorated with it. It adds the complexity of additional scoping.

:three: MainActor-isolated task:

Task { @MainActor in settings.isFeatureEnabled = true }

This has all the same problems as #2.

Why can't I just set the property?

6 Likes