{"id":35863,"date":"2022-05-12T14:13:52","date_gmt":"2022-05-12T18:13:52","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=35863"},"modified":"2022-05-13T15:28:20","modified_gmt":"2022-05-13T19:28:20","slug":"mainactor-not-guaranteed","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2022\/05\/12\/mainactor-not-guaranteed\/","title":{"rendered":"@MainActor Not Guaranteed"},"content":{"rendered":"<p><a href=\"https:\/\/oleb.net\/2022\/how-mainactor-works\/\">Ole Begemann<\/a>:<\/p>\n<blockquote cite=\"https:\/\/oleb.net\/2022\/how-mainactor-works\/\">\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/swift\/mainactor#\"><code>@MainActor<\/code><\/a> is a Swift annotation to coerce a function to always run on the main thread <em>and<\/em> to enable the compiler to verify this. How does this work? In this article, I&rsquo;m going to reimplement <code>@MainActor<\/code> in a slightly simplified form for illustration purposes, mainly to show how little &ldquo;magic&rdquo; there is to it. <a href=\"https:\/\/github.com\/apple\/swift\/blob\/main\/stdlib\/public\/Concurrency\/MainActor.swift\">The code of the real implementation<\/a> in the Swift standard library is available in the Swift repository.<\/p>\n<p>[&#8230;]<\/p>\n<p><code>@MainActor<\/code> already uses the unofficial ability for an actor to provide a custom executor, and we&rsquo;re going to do the same for our reimplementation. A serial executor that runs its job on the main dispatch queue is implemented as follows.<\/p>\n<p>[&#8230;]<\/p>\n<p><a href=\"https:\/\/github.com\/rjmccall\/swift-evolution\/blob\/custom-executors\/proposals\/0000-custom-executors.md\">John McCall&rsquo;s draft proposal for custom executors<\/a> is worth reading, particularly <a href=\"https:\/\/github.com\/rjmccall\/swift-evolution\/blob\/custom-executors\/proposals\/0000-custom-executors.md#philosophy-of-thread-usage\">the philosophy section<\/a>.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/blog.hobbyistsoftware.com\/2022\/01\/mainactor-not-guaranteed\/\">Rob Jonson<\/a> (<a href=\"https:\/\/twitter.com\/ConfusedVorlon\/status\/1483090699390181377\">tweet<\/a>):<\/p>\n<blockquote cite=\"https:\/\/blog.hobbyistsoftware.com\/2022\/01\/mainactor-not-guaranteed\/\">\n<p>For good measure &#x2013; I mark the task as @MainActor.<\/p>\n<p>My expectation was the following<\/p>\n<ol><li>in doWork(), it would return off the main thread after Background().go()<\/li><li>@MainActor annotation would ensure that calling self.mainDate would happen on the main thread &#x2013; or there would be a compiler error<\/li><li>@MainActor annotation would ensure that calling self.storedDate would happen on the main thread &#x2013; or there would be a compiler error<\/li><\/ol>\n<p>#2 and #3 are false.<\/p>\n<p>[&#8230;]<\/p>\n<p>Bizarrely &#x2013; If include a print statement in my task, then everything <em>does<\/em> run on the main thread!!!<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/twitter.com\/olebegemann\/status\/1421144304127463427\">Ole Begemann<\/a>:<\/p>\n<blockquote cite=\"https:\/\/twitter.com\/olebegemann\/status\/1421144304127463427\">\n<p>If you&rsquo;re writing Swift concurrency code, add these compiler flags:<\/p>\n<pre>-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks<\/pre>\n<p>(in Xcode: Other Swift Flags)<\/p>\n<p>Warnings in Swift 5.5 identify unsafe constructs, will become errors in Swift 6.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/blog.hobbyistsoftware.com\/2022\/01\/mainactor-not-guaranteed\/\">Rob Jonson<\/a>:<\/p>\n<blockquote cite=\"https:\/\/blog.hobbyistsoftware.com\/2022\/01\/mainactor-not-guaranteed\/\">\n<p>Moving the exact same code out of the NSViewController and into a separate class (that inherits from nothing) causes the expected compiler warnings to kick in.<\/p>\n<p>It seems that my model is &lsquo;Sendable&rsquo; &#x2013; so now the compiler can do magic.<\/p>\n<p>This feels like an important limitation that should be in <strong>BIG BOLD LETTERS<\/strong> in the documentation&#8230;<\/p>\n<\/blockquote>\n\n<p>See also: <a href=\"https:\/\/github.com\/apple\/swift\/issues\/57114\">@MainActor ignored by the compiler<\/a>.<\/p>\n\n<p id=\"mainactor-not-guaranteed-update-2022-05-13\">Update (2022-05-13): See also: <a href=\"https:\/\/twitter.com\/depth42\/status\/1525102311269355520\">Frank Illenberger<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Ole Begemann: @MainActor is a Swift annotation to coerce a function to always run on the main thread and to enable the compiler to verify this. How does this work? In this article, I&rsquo;m going to reimplement @MainActor in a slightly simplified form for illustration purposes, mainly to show how little &ldquo;magic&rdquo; there is to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2022-05-12T18:13:54Z","apple_news_api_id":"bb3431f5-5b5d-4fcb-b4e2-3f165e8b1c4c","apple_news_api_modified_at":"2022-05-13T19:28:24Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAA==","apple_news_api_share_url":"https:\/\/apple.news\/AuzQx9VtdT8u04j8WXoscTA","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":[131,800,31,2078,30,2077,71,2200],"class_list":["post-35863","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-bug","tag-concurrency","tag-ios","tag-ios-15","tag-mac","tag-macos-12","tag-programming","tag-swift-concurrency"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35863","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=35863"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35863\/revisions"}],"predecessor-version":[{"id":35870,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/35863\/revisions\/35870"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=35863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=35863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=35863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}