{"id":44251,"date":"2024-07-29T16:09:31","date_gmt":"2024-07-29T20:09:31","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=44251"},"modified":"2024-07-29T16:09:31","modified_gmt":"2024-07-29T20:09:31","slug":"actor-reentrancy-in-swift","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/07\/29\/actor-reentrancy-in-swift\/","title":{"rendered":"Actor Reentrancy in Swift"},"content":{"rendered":"<p><a href=\"https:\/\/www.donnywals.com\/actor-reentrancy-in-swift-explained\/\">Donny Wals<\/a> (<a href=\"https:\/\/chaos.social\/@donnywals\/112252396433853407\">Mastodon<\/a>):<\/p>\n<blockquote cite=\"https:\/\/www.donnywals.com\/actor-reentrancy-in-swift-explained\/\">\n<p>When you start learning about <a href=\"https:\/\/www.donnywals.com\/an-introduction-to-synchronizing-access-with-swifts-actors\/\" title=\"An introduction to synchronizing access with Swift's actors\">actors in Swift<\/a>, you&rsquo;ll find that explanations will always contain something along the lines of &ldquo;Actors protect shared mutable state by making sure the actor only does one thing at a time&rdquo;. As a single sentence summary of actors, this is great but it misses an important nuance. While it&rsquo;s true that actors do only one thing at a time, they don&rsquo;t always execute function calls <a href=\"https:\/\/www.donnywals.com\/what-does-atomic-mean-in-programming\/\" title=\"What does atomic mean in programming?\">atomically<\/a>.<\/p>\n<p>[&#8230;]<\/p>\n<p>However, when we introduce an async function that has a suspension point the actor will not sit around and wait for the suspension point to resume. Instead, the actor will grab the next message in its &ldquo;mailbox&rdquo; and start making progress on that instead. When the thing we were awaiting returns, the actor will continue working on our original function.<\/p>\n<p>[&#8230;]<\/p>\n<p>Things become trickier when you try and make your actor into a serial queue that runs async tasks. In a future post I&rsquo;d like to dig into why that&rsquo;s so tricky and explore possible solutions.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/hachyderm.io\/@holly\/112836650721034120\">Holly Borla<\/a>:<\/p>\n<blockquote cite=\"https:\/\/hachyderm.io\/@holly\/112836650721034120\">\n<p>I think something like an async queue should be included in the concurrency library. The <code>AsyncStream<\/code> boilerplate is repeated everywhere for this sort of pattern, and we should make it easier to write because it&rsquo;s a pattern that a lot of people need when order has to be guaranteed.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@krzyzanowskim\/112846967908305470\">Marcin Krzyzanowski<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@krzyzanowskim\/112846967908305470\">\n<p>what&rsquo;s worse:<\/p>\n<ul><li>undetectable actor reenteancy bugs that freeze the process<\/li>\n<li>data race bugs that crash the app<\/li><\/ul>\n<p>can&rsquo;t decide. hate both. one was not a big deal until recently in Swift<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.cloud\/@drewmccormack\/112845984614616712\">Drew McCormack<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.cloud\/@drewmccormack\/112845984614616712\">\n<p>When most people first learn about actors, I think they expect it to work this way, ie, that each call completes, and the next begins, like a class with a serial queue. So I don&rsquo;t think there is anything fundamentally wrong with the idea. Of course, what you open your door to are reentrances which can deadlock. Apple chose their evil, namely races, over the alternative, deadlocking. I find races harder to debug in general.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@helge\/112848359167053637\">Helge He&szlig;<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@helge\/112848359167053637\"><p>It is pretty clear that the reentrancy issue of Swift &ldquo;actors&rdquo; exists specifically to avoid the chance of deadlock, which an atomic, async, actor has.<\/p><p>I can&rsquo;t say whether that is better or worse in practice, I&rsquo;d say probably worse. Maybe it would have been better if an actor wouldn&rsquo;t be allowed to issue async calls, and hence have real-actor-like atomic behaviour guaranteed. I&rsquo;m pretty sure a ton of people are going to shoot themselves in the foot over the reentrancy issue.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.cloud\/@drewmccormack\/112852652526241969\">Drew McCormack<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.cloud\/@drewmccormack\/112852652526241969\">\n<p>Seems you can write a Swift macro to serialize execution of an async func. Trick is to embed a queue in the func, generating the appropriate return values etc.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@totzek\/112847308702360761\">Tobias<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@totzek\/112847308702360761\">\n<p>Since the introduction of Actors, the Swift community is highly focused on them. I very rarely see Stuff like &ldquo;Here is this cool new API and what you can do with it&rdquo; anymore but only &ldquo;How do I avoid data races and how does this Actor stuff actually work&rdquo;. It is sad.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@mattiem\/112858781454498793\">Matt Massicotte<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@mattiem\/112858781454498793\"><p>I took a shot at <a href=\"https:\/\/github.com\/mattmassicotte\/Lock\">building an async-compatible lock<\/a>.<\/p><p>Great for dealing with actor reentrancy. It&rsquo;s kinda hard to use right now, becuase it cannot be built with the compiler in Xcode 16b4. I&rsquo;d still love to hear what you think, even just about the concept.<\/p><\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/07\/22\/swift-6-announced\/\">Swift 6 Announced<\/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<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/07\/01\/concurrencyplus\/\">ConcurrencyPlus<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2021\/03\/18\/swift-proposal-actors\/\">Swift Proposal: Actors<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Donny Wals (Mastodon): When you start learning about actors in Swift, you&rsquo;ll find that explanations will always contain something along the lines of &ldquo;Actors protect shared mutable state by making sure the actor only does one thing at a time&rdquo;. As a single sentence summary of actors, this is great but it misses an important [&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-07-29T20:09:35Z","apple_news_api_id":"52b532ec-4b90-4af8-aee6-8f6ea2ac1d7e","apple_news_api_modified_at":"2024-07-29T20:09:35Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AUrUy7EuQSviu5o9uoqwdfg","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":[800,31,2321,30,2385,71,2200,901],"class_list":["post-44251","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-concurrency","tag-ios","tag-ios-17","tag-mac","tag-macos-14-sonoma","tag-programming","tag-swift-concurrency","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/44251","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=44251"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/44251\/revisions"}],"predecessor-version":[{"id":44252,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/44251\/revisions\/44252"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=44251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=44251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=44251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}