Design Priorities for the Swift 6 Language Mode

Sure, I'm happy to summarize here, since I made the original post. In brief:

This struct is not actor-isolated:

struct MyView: View {
  @State private var x = 0

  var body: some View {
    Text("\(x)")
  }
}

This struct is actor-isolated (to the main actor):

struct MyView: View {
  @StateObject private var model = SomeModel()

  var body: some View {
    Text("\(model.x)")
  }
}

Simply changing @State to @StateObject changed the actor isolation of the entire containing type. It's because struct StateObject is declared @MainActor, but struct State is not. Applying an actor-isolated property wrapper to a property implicitly propagates that isolation up to the containing type, which in turn propagates it to all sibling declarations of the property (including all other properties and functions within the type).

I made a more complete argument in the other thread, so I'll just summarize here. This upward propagation of actor isolation from a property to the containing type is not well justified by SE-0316 where it was introduced, and has been the source of a lot of confusion (to mention just a couple recent examples). It even inhibits the adoption of @MainActor annotations in some places, because the actor-isolation becomes "viral", spreading further than the author intended. Nobody has commented in favor of the current behavior; the confusion and surprise is universal in all comments.

Changing this behavior (no longer propagating the actor isolation to the containing type) would be source-breaking, but there may be ways to mitigate that breakage for particular frameworks (e.g. SwiftUI). But since it's source-breaking, it would need to happen in a new language mode, so Swift 6 would be the right time to do it.

27 Likes