{"id":50122,"date":"2025-11-20T16:17:12","date_gmt":"2025-11-20T21:17:12","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=50122"},"modified":"2025-12-01T16:13:18","modified_gmt":"2025-12-01T21:13:18","slug":"no-mainactor-by-default","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2025\/11\/20\/no-mainactor-by-default\/","title":{"rendered":"(No) MainActor by Default"},"content":{"rendered":"<p><a href=\"https:\/\/www.massicotte.org\/blog\/mainactor-by-default\/\">Matt Massicotte<\/a> (<a href=\"https:\/\/mastodon.social\/@mattiem\/115583788887195844\">Mastodon<\/a>):<\/p>\n<blockquote cite=\"https:\/\/www.massicotte.org\/blog\/mainactor-by-default\/\"><p>Swift 6.2 gives you the ability make <code>MainActor<\/code> the default isolation. Unlike the rest of the features introduced as part of &ldquo;<a href=\"https:\/\/github.com\/swiftlang\/swift-evolution\/blob\/main\/visions\/approachable-concurrency.md\">Approachable Concurrency<\/a>&rdquo;, 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.<\/p><p>[&#8230;]<\/p><p>Well I have made up my mind, at least for now. We should not. I&rsquo;m not sure we should even have the ability to do so.<\/p><p>[&#8230;]<\/p><p>But when you finally encounter concurrency, <strong>and you almost certainly will<\/strong>, a default of <code>MainActor<\/code> can make those encounters much more difficult to understand and address.<\/p><p>[&#8230;]<\/p><p>(I also did a <a href=\"https:\/\/youtu.be\/eqeDPIK2Msc\">whole talk<\/a> on this if that&rsquo;s interesting.)<\/p><\/blockquote>\n\n<p>I still find this all rather confusing, but I&rsquo;m inclined to agree with his argument. I understood the original motivation as sort of progressive disclosure. You shouldn&rsquo;t have to deal with concurrency at all if you don&rsquo;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 <code>MainActor<\/code> (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.)<\/p>\n\n<p><a href=\"https:\/\/mastodon.social\/@ryanbooker\/115583932987852536\">Ryan Booker<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@ryanbooker\/115583932987852536\"><p>I&rsquo;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.<\/p><p>So I&rsquo;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&rsquo;s suggestion!<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@schwa\/115583960030200287\">Jonathan Wight<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@schwa\/115583960030200287\">\n<p>The most vocal Swift Concurrency expert outside of Apple is recommending to avoid MainActor default isolation and you&rsquo;re left wondering what is even the point.<\/p>\n<\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2025\/11\/07\/mainactor-assumeisolated-preconcurrency-and-isolated-conformances\/\">MainActor.assumeIsolated, Preconcurrency, and Isolated Conformances<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2025\/11\/03\/swift-6-2-approachable-concurrency\/\">Swift 6.2: Approachable Concurrency<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/11\/25\/swift-vision-improving-the-approachability-of-data-race-safety\/\">Swift Vision: Improving the Approachability of Data-Race Safety<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/09\/19\/swift-6\/\">Swift 6<\/a><\/li>\n<\/ul>\n\n<p id=\"no-mainactor-by-default-update-2025-11-21\">Update (<a href=\"#no-mainactor-by-default-update-2025-11-21\">2025-11-21<\/a>): <a href=\"https:\/\/mastodon.social\/@mattiem\/115587333255085227\">Matt Massicotte<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@mattiem\/115587333255085227\">\n<p>I want to add though, that I find it really confusing to look at MainActor default as some kind of alternative path towards a 6 migration. Because it&rsquo;s really just automation, it does not change the nature of the problems you have to consider.<\/p>\n<\/blockquote>\n\n<p id=\"no-mainactor-by-default-update-2025-12-01\">Update (<a href=\"#no-mainactor-by-default-update-2025-12-01\">2025-12-01<\/a>): <a href=\"https:\/\/mastodon.social\/@tonyarnold\/115619470888867877\">Tony Arnold<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@tonyarnold\/115619470888867877\"><p>I&rsquo;m trying out a <code>MainActor<\/code> by default project today, and I can&rsquo;t use <code>LocalizedStringResources<\/code> that are extracted from my <tt>xcstrings<\/tt> catalog &#x1F633;<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/www.avanderlee.com\/xcode\/the-7-changes-i-do-for-every-new-xcode-project\/\">Antoine van der Lee<\/a>:<\/p>\n<blockquote cite=\"https:\/\/www.avanderlee.com\/xcode\/the-7-changes-i-do-for-every-new-xcode-project\/\">\n<p>By enabling approachable concurrency and setting the default actor isolation to <code>MainActor<\/code>, you immediately establish a safer and more predictable foundation for Swift concurrency. It also makes your project more resilient to future Swift updates and encourages a consistent mental model from day one. You can learn more about this concept in my article <a href=\"https:\/\/www.avanderlee.com\/concurrency\/approachable-concurrency-in-swift-6-2-a-clear-guide\/\">Approachable Concurrency in Swift 6.2: A Clear Guide<\/a>.<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Matt Massicotte (Mastodon): Swift 6.2 gives you the ability make MainActor the default isolation. Unlike the rest of the features introduced as part of &ldquo;Approachable Concurrency&rdquo;, 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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2025-11-20T21:17:16Z","apple_news_api_id":"49b46130-f23f-4e9e-8702-2f8a73d38034","apple_news_api_modified_at":"2025-12-01T21:13:23Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAw==","apple_news_api_share_url":"https:\/\/apple.news\/ASbRhMPI_Tp6HAi-Kc9OANA","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[31,2741,30,2742,71,2200,901],"class_list":["post-50122","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-ios","tag-ios-26","tag-mac","tag-macos-tahoe-26","tag-programming","tag-swift-concurrency","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/50122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=50122"}],"version-history":[{"count":5,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/50122\/revisions"}],"predecessor-version":[{"id":50261,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/50122\/revisions\/50261"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=50122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=50122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=50122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}