@MainActor should make the function async

The @MainActor attribute should be a guarantee that a method is called on the main thred, yet it is not.

If you don't mark a @MainActor func explicitly as async, it is still possible to call it from some other queue/actor.

  1. Either the compiler should enforce that all @MainActor annotated funcs have the async attribute
  2. Or the compiler should make all @MainActor methods implicitly async

Otherwise @MainActor is more of a suggestion than a guarantee.

The compiler ensures that all calls to @MainActor methods are implicitly async unless called from something that is also @MainActor. However, that checking is being phased in over multiple releases to avoid breaking existing code that looks like this:

// Existing code that calls the completion on the main thread,
// but is not yet annotated with `@MainActor`
func fetchUser(_ completion: @escaping (User)->Void) {
  // ...
}

func viewDidAppear() {
  fetchUser() { (user) in
    // We know that this always runs on the main thread,
    // but `fetchUser`'s parameter has not been annotated
    // with @MainActor, so the *compiler* doesn't know it
    // yet. 
    //
    // If the compiler enforced an 'await' here, it would 
    // break too much existing code
    self.label.text = user.name
  }
}

I believe that the plan is to produce a warning about the above code in Swift 5.7, and then upgrade it to a hard error whenever Swift 6.0 comes out. It would also be an error right now, in Swift 5.6, if the surrounding code uses any other concurrency annotations to indicate that it is concurrency-aware.

But yes, for the moment @MainActor is a suggestion but not yet a guarantee.

1 Like