{"id":42309,"date":"2024-03-01T14:19:05","date_gmt":"2024-03-01T19:19:05","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=42309"},"modified":"2024-03-01T14:19:05","modified_gmt":"2024-03-01T19:19:05","slug":"how-the-swift-compiler-knows-that-dispatchqueue-main-implies-mainactor","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/03\/01\/how-the-swift-compiler-knows-that-dispatchqueue-main-implies-mainactor\/","title":{"rendered":"How the Swift Compiler Knows That DispatchQueue.main Implies @MainActor"},"content":{"rendered":"<p><a href=\"https:\/\/oleb.net\/2024\/dispatchqueue-mainactor\/\">Ole Begemann<\/a> (<a href=\"https:\/\/chaos.social\/@ole\/112016322771055797\">Mastodon<\/a>):<\/p>\n<blockquote cite=\"https:\/\/oleb.net\/2024\/dispatchqueue-mainactor\/\">\n<p>A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on <code>DispatchQueue.main<\/code>, <em>in exactly that spelling<\/em>.<\/p>\n<p>[&#8230;]<\/p>\n<p>Fun fact: since this is a purely syntax-based check, if you define your own type named <code>DispatchQueue<\/code>, give it a static <code>main<\/code> property and a function named <code>async<\/code> that takes a closure, the compiler will apply the same &ldquo;fix&rdquo; to it. This is NOT recommended[&#8230;]<\/p>\n<p>[&#8230;]<\/p>\n<p>The biggest benefit of Swift&rsquo;s concurrency model over what we had before is that so many things are statically known at compile time. It&rsquo;s a shame that the compiler <em>knows<\/em> on which executor a particular line of code will run, but none of the tools seem to be able to show me this. Instead, I&rsquo;m forced to hunt for <code>@MainActor<\/code> annotations and hidden attributes in superclasses, protocols, etc. This feels especially problematic during the Swift 5-to-6 transition phase we&rsquo;re currently in where it&rsquo;s so easy to misuse concurrency and <em>not<\/em> get a compiler error (and sometimes not even a warning if you forget to enable strict concurrency checking).<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/sfba.social\/@dgregor79\/112018548124986350\">Doug Gregor<\/a>:<\/p>\n<blockquote cite=\"https:\/\/sfba.social\/@dgregor79\/112018548124986350\">\n<p>The <code>@MainActor<\/code> attribute is the general thing, and if <code>DispatchQueue.main<\/code> returned a <code>MainDispatchQueue<\/code> type whose async method took a <code>@MainActor<\/code> closure, we&rsquo;d be all set. The problem with this specific case is that <code>DispatchQueue.main<\/code> already has a type (<code>DispatchQueue<\/code>), and you can&rsquo;t change that type without affecting source compatibility. So you would need some generalization that tries to carry <code>MainActor<\/code>-ness along with the value. I suspect that such a generalization would generalize to, basically, just this API, so I didn&rsquo;t pursue it. Given the choice between breaking source compatibility for <code>DispatchQueue.main<\/code> (which is everywhere), inventing a bespoke feature for these cases alone, or allow-listing this pattern to help more code &ldquo;just work&rdquo;&#8230; I think this was rhetorical right call. Maybe we should have also deprecated this pattern over to move to an API that does take a <code>@MainActor<\/code> closure, so the allow-list would become irrelevant over time.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/chaos.social\/@holly@hachyderm.io\/112017734164769666\">Holly Borla<\/a>:<\/p>\n<blockquote cite=\"https:\/\/chaos.social\/@holly@hachyderm.io\/112017734164769666\">\n<p>You might be interested in <a href=\"https:\/\/forums.swift.org\/t\/closure-isolation-control\/70378\">this pitch<\/a> which replaces <code>@_inheritActorContext<\/code> with a proper, non-underscored <code>@inheritsIsolation<\/code> attribute, including replacement in <code>Task.init<\/code>.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/layer8.space\/@teilweise\/112019987516941126\">Der Teilweise<\/a>:<\/p>\n<blockquote cite=\"https:\/\/layer8.space\/@teilweise\/112019987516941126\">\n<p>Everything about warnings is completely broken in Xcode.<\/p>\n<p>When I turn on the concurrency warnings in 15.3&szlig;3, I get ~40 warnings that disappear half a second after I click them (and come back when I switch away from the file).<\/p>\n<\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/03\/01\/where-view-task-gets-its-main-actor-isolation-from\/\">Where View.task Gets Its Main-actor Isolation From<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2023\/10\/02\/the-bleeding-edge-of-swift-concurrency\/\">The Bleeding Edge of Swift Concurrency<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Ole Begemann (Mastodon): A bit of experimentation reveals that it is in fact a relatively coarse source-code-based check that singles out invocations on DispatchQueue.main, in exactly that spelling. [&#8230;] Fun fact: since this is a purely syntax-based check, if you define your own type named DispatchQueue, give it a static main property and a function [&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":"2024-03-01T19:19:08Z","apple_news_api_id":"86027dad-fa07-4314-98b2-746ee26482f4","apple_news_api_modified_at":"2024-03-01T19:19:08Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AhgJ9rfoHQxSYsnRu4mSC9A","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":[255,880,31,2321,30,2385,2200,901,226],"class_list":["post-42309","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-compiler","tag-grand-central-dispatch-gcd","tag-ios","tag-ios-17","tag-mac","tag-macos-14-sonoma","tag-swift-concurrency","tag-swift-programming-language","tag-xcode"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42309","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=42309"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42309\/revisions"}],"predecessor-version":[{"id":42310,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/42309\/revisions\/42310"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=42309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=42309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=42309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}