{"id":27164,"date":"2019-11-02T15:22:48","date_gmt":"2019-11-02T19:22:48","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=27164"},"modified":"2019-11-02T21:24:09","modified_gmt":"2019-11-03T01:24:09","slug":"efficiently-mutating-nested-swift-data-structures","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2019\/11\/02\/efficiently-mutating-nested-swift-data-structures\/","title":{"rendered":"Efficiently Mutating Nested Swift Data Structures"},"content":{"rendered":"<p><a href=\"https:\/\/twitter.com\/radexp\/status\/1187012331567550466\">Radek Pietruszewski<\/a>:<\/p>\n<blockquote cite=\"https:\/\/twitter.com\/radexp\/status\/1187012331567550466\">\n<p>That feel when you&rsquo;re profiling a React Native app, and you&rsquo;re sure JavaScript is the source of your problems&#8230; but no, it&rsquo;s ridiculously misoptimized Swift doing&#8230; well&#8230; nothing much for two minutes.<\/p>\n<p>[&#8230;]<\/p>\n<p>Code does something that <em>seems<\/em> completely reasonable, but ends up creating a new copy of a large <code>Set<\/code> 10,000s times. Not entirely sure if Swift is supposed to be smart enough to figure out that it can safely mutate it, or it&rsquo;s programmer&rsquo;s responsibility.<\/p>\n<p>The intention is to insert to a <code>Set<\/code> that&rsquo;s in a <code>Dictionary<\/code> that&rsquo;s a mutable variable on a class<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/twitter.com\/jckarter\/status\/1189929997370179584\">Joe Groff<\/a>:<\/p>\n<blockquote cite=\"https:\/\/twitter.com\/jckarter\/status\/1189929997370179584\">\n<p>Older versions could not modify values in dictionaries without copying them, but 5.0 and later should be able to.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/twitter.com\/lorentey\/status\/1190025478071083009\">Karoy Lorentey<\/a>:<\/p>\n<blockquote cite=\"https:\/\/twitter.com\/lorentey\/status\/1190025478071083009\">\n<p>Yep, <code>Array<\/code> &amp; <code>Dictionary<\/code> both support in-place mutations. For <code>Dictionary<\/code>, the recommended way is to use the defaulting subscript. E.g., this won&rsquo;t make a CoW copy:<\/p>\n<pre>sets[key, default: Set()].insert(foo)<\/pre>\n<p>But this will:<\/p>\n<pre>var tmp = sets[key]\ntmp.insert(foo)\nsets[key] = tmp<\/pre>\n<p>The <code>Dictionary.Values<\/code> collection also supports this, and it may come handy if you need to distinguish between existing and new keys:<\/p>\n<pre>if let i = sets.index(forKey: key) {\n  sets.values[i].insert(foo)\n} else {\n  fatalError(\"Unknown key \\(key)\")\n}<\/pre>\n<\/blockquote>\n\n<p>I&rsquo;ve written about this before, but I think it&rsquo;s worth re-emphasizing how this works. It&rsquo;s counterintuitive and unusual in programming for introducing a temporary variable, as people often do when debugging, to radically change the behavior of the code. Copy-on-write is a leaky abstraction.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2019\/02\/07\/fast-safe-mutable-state-in-swift-5\/\">Fast Safe Mutable State in Swift 5<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2016\/11\/14\/swift-copy-on-write-psa-mutating-dictionary-entries\/\">Swift Copy-on-Write PSA: Mutating Dictionary Entries<\/a><\/li>\n<\/ul>\n\n<p id=\"efficiently-mutating-nested-swift-data-structures-update-2019-11-02\">Update (2019-11-02): See also: <a href=\"https:\/\/twitter.com\/lorentey\/status\/1190729408975233024\">Karoy Lorentey<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Radek Pietruszewski: That feel when you&rsquo;re profiling a React Native app, and you&rsquo;re sure JavaScript is the source of your problems&#8230; but no, it&rsquo;s ridiculously misoptimized Swift doing&#8230; well&#8230; nothing much for two minutes. [&#8230;] Code does something that seems completely reasonable, but ends up creating a new copy of a large Set 10,000s times. [&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":"2019-11-02T19:22:52Z","apple_news_api_id":"39212c61-3127-4ae2-b4bb-81a0101198a3","apple_news_api_modified_at":"2019-11-03T01:24:15Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/AOSEsYTEnSuK0u4GgEBGYow","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,1667,26,138,71,901],"class_list":["post-27164","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-ios","tag-ios-13","tag-iosapp","tag-optimization","tag-programming","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/27164","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=27164"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/27164\/revisions"}],"predecessor-version":[{"id":27166,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/27164\/revisions\/27166"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=27164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=27164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=27164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}