(No) MainActor by Default
Swift 6.2 gives you the ability make
MainActorthe default isolation. Unlike the rest of the features introduced as part of “Approachable Concurrency”, this is a long-term mode. It is optional and will remain so. However, this mode is enabled for new app targets in Xcode 26. And many people take this as a very strong signal from Apple, myself included.[…]
Well I have made up my mind, at least for now. We should not. I’m not sure we should even have the ability to do so.
[…]
But when you finally encounter concurrency, and you almost certainly will, a default of
MainActorcan make those encounters much more difficult to understand and address.[…]
(I also did a whole talk on this if that’s interesting.)
I still find this all rather confusing, but I’m inclined to agree with his argument. I understood the original motivation as sort of progressive disclosure. You shouldn’t have to deal with concurrency at all if you don’t need your code to be concurrent. But for most real apps you will have to understand and use the full Swift Concurrency. If opting in to MainActor (the keyword, not the default isolation) is easier than opting out, is that really helping in the end? Why start down a garden path that leads to a cliff? And is having the simple mode worth the confusion of having two modes, and having to keep straight which module is using which? (This is on top of having separate modes for Swift 5 and 6.)
I’ve seen quite a few people saying something similar. What worries me is that not only is MainActor the default now, the WWDC videos introducing it are quite clear that Apple think you should make your App target and UI based modules all MainActor by default, with non UI modules nonisolated by default.
So I’m worried about fighting the tide, but also the idea that you have two inverted concurrency systems to reason about in one code base if you follow Apple’s suggestion!
The most vocal Swift Concurrency expert outside of Apple is recommending to avoid MainActor default isolation and you’re left wondering what is even the point.
Previously:
- MainActor.assumeIsolated, Preconcurrency, and Isolated Conformances
- Swift 6.2: Approachable Concurrency
- Swift Vision: Improving the Approachability of Data-Race Safety
- Swift 6
2 Comments RSS · Twitter · Mastodon
Trying to figure out what the issue is here (I think this helps declutter a lot of code that needs not be concurrent, or concurrency is hidden behind public API that doesn't expose the concurrent implementation detail).
Apple made concurrency so convoluted and confusing, that it is now trying to make it "approachable" by hiding a lot of the convolution and confusion, but if they unconfuse it, it is going to … confuse people further? Well, isn't that the story of Swift in general.
> Changing the default isolation fundamentally alters the nature of a program's relationship with the concurrency system. It demands you now be able to recognize and understand when MainActor is inappropriate. This can be very difficult.
So we're back to the developer having to juggle the neurons they hopefully have to make concurrency work. I guess that is an undesirable end result in some Swift crowds.
Wake me up in 18 months when this shit show has hopefully settled down a bit.
In the meantime, I'll try to avoid Swift Concurrency as much as feasible.
I think I can handle one unnecessary Apple API migration per year, and I just finished migrating from StoreKit1 to StoreKit2, so Swift Concurrency can be a task for early 2027.
Lots of work, for relatively little user or developer benefit? No thanks.