{"id":850,"date":"2022-01-04T19:38:48","date_gmt":"2022-01-04T17:38:48","guid":{"rendered":"https:\/\/www.juustila.com\/antti\/?p=850"},"modified":"2022-01-04T19:38:48","modified_gmt":"2022-01-04T17:38:48","slug":"swift-tree-structures-value-types-enums-and-classes","status":"publish","type":"post","link":"https:\/\/www.juustila.com\/antti\/2022\/01\/04\/swift-tree-structures-value-types-enums-and-classes\/","title":{"rendered":"Swift tree structures: value types, enums and classes"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">What if you need to define a tree like structure of data elements in Swift? For example you might use a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Binary_search_tree\" target=\"_blank\" rel=\"noreferrer noopener\">Binary Search Tree<\/a> to keep track of unique words in a book file:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-medium\"><img loading=\"lazy\" decoding=\"async\" width=\"238\" height=\"300\" src=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/tree-238x300.png\" alt=\"A tree structure where each node in the tree has optional two child nodes, left and right. Each node has two values: the word found in the book, and the count how many times the word appeared in the book.\" class=\"wp-image-851\" srcset=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/tree-238x300.png 238w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/tree-768x968.png 768w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/tree-535x674.png 535w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/tree.png 784w\" sizes=\"auto, (max-width: 238px) 85vw, 238px\" \/><figcaption><em>An example of a binary search tree with unique word counts from a text file.<\/em><\/figcaption><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since value types are often preferred in Swift, you could use a struct. The Node struct contains the word, the count of it in the book, a key to manage the tree, and optional left and right child nodes of the tree.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"321\" src=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-1024x321.png\" alt=\"struct Node {\n   let key: Int\n   let word: String\n   var count: Int\n\n   var leftChild: Node?\n   var rightChild: Node?\n\n   init(_ word: String) {\n      key = word.hashValue\n      self.word = word\n      count = 1\n   }\n}\" class=\"wp-image-853\" srcset=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-1024x321.png 1024w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-300x94.png 300w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-768x241.png 768w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-1536x482.png 1536w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17-535x168.png 535w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.37.17.png 1886w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">But as you can see from the error message &#8220;Value type &#8216;Node&#8217; cannot have a stored property that recursively contains it&#8221; &#8212; <em>recursive<\/em> value types are not supported in Swift. A Node in the tree struct cannot contain the left and right child nodes when using value types. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What to do? You have (at least) two options:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Use the <code>enum<\/code> type with associated values.<\/li><li>Use classes.<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">With <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/Enumerations.html#\" target=\"_blank\">Swift enums<\/a>, you can define two states for the enumeration. Either a) the node in the tree is Empty (there is no node) or b) it has <em>associated values<\/em> in a Node &#8212; the word, the word count, key used to arrange the nodes in the tree by the word hash value, and the optional left and right subtrees:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"348\" src=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-1024x348.png\" alt=\"indirect enum EnumTreeNode {\n   case Empty\n   case Node(left: EnumTreeNode, hash: Int, word: String, count: Int, right: EnumTreeNode)\n\n   init() {\n      self = .Empty\n   }\n\n   init(_ word: String) {\n      self = .Node(left: .Empty, hash: word.hashValue, word: word, count: 1, right: .Empty)\n   }\n\n   func accept(_ visitor: Visitor) throws {\n      try visitor.visit(node: self)\n   }\n}\" class=\"wp-image-856\" srcset=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-1024x348.png 1024w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-300x102.png 300w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-768x261.png 768w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-1536x522.png 1536w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26-535x182.png 535w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-19.07.26.png 1948w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><figcaption><em>A tree node as an enumeration with associated values.<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">When defining recursive enumerations, you must use the <code>indirect<\/code> keyword to indicate recursion in the enumeration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The other option is to use <strong>classes<\/strong>, which are reference type elements in Swift:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"329\" src=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-1024x329.png\" alt=\"final class TreeNode {\n   let key: Int\n   let word: String\n   var count: Int\n\n   var left: TreeNode?\n   var right: TreeNode?\n\n   init(_ word: String) {\n      self.key = word.hashValue\n      self.word = word\n      count = 1\n   }\" class=\"wp-image-855\" srcset=\"https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-1024x329.png 1024w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-300x96.png 300w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-768x246.png 768w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-1536x493.png 1536w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14-535x172.png 535w, https:\/\/www.juustila.com\/antti\/wp-content\/uploads\/2022\/01\/Nayttokuva-2022-1-4-kello-18.56.14.png 1714w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You can read more about Swift <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/ClassesAndStructures.html\" target=\"_blank\">structs and classes from here<\/a> if you are unfamiliar with them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check out the full implementation of both class based and enum based solutions from <a href=\"https:\/\/github.com\/anttijuu\/BooksAndWords\/tree\/main\/BSTree\" target=\"_blank\" rel=\"noreferrer noopener\">this GitHub repository<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, are there any other differences in the enum and class implementations, than the differences in code? <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s check out. First run below is using the enum implementation, and the second one is executed using the class based implementation.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>> swift build -c release\n> .build\/release\/bstree ..\/samples\/tiny.txt ..samples\/ignore-words.txt 100\n...\nCount of words: 44, count of unique words: 32\n>>>> Time 0.0008840560913085938 secs.\n\n\n> swift build -c release\n> .build\/release\/bstree ..\/samples\/tiny.txt ..samples\/ignore-words.txt 100\n...\nCount of words: 44, count of unique words: 32\n>>>> Time 0.0009189844131469727 secs.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So far so good. Both implementations work (not all results not shown above) and seem to be quite fast. The tiny text file contains only 44 words of which 32 are unique.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But when executing both implementations with a larger 16MB file with 2674582 words of which 97152 are unique&#8230;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>> .build\/release\/bstree ..\/samples\/Bulk.txt ..samples\/ignore-words.txt 100\n...\nCount of words: 2674582, count of unique words: 97152\n >>>> Time 16.52852702140808 secs.\n\n\n> .build\/release\/bstree ..\/samples\/Bulk.txt ..samples\/ignore-words.txt 100\nCount of words: 2674582, count of unique words: 97152\n >>>> Time 3.5031620264053345 secs.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can see that the first enum based implementation took 16.5 secs to process the same file the class based implementation only took 3.5 secs to process. This is a significant difference. Why this happens?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Swift enums behave like value types. When the algorithm reads a word from the book file, it searches if it already exists in the tree. If yes, the old enum value is replaced with the new one in the tree. This results in copying the tree since it is now mutated. The <a href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/ClassesAndStructures.html#ID88\" target=\"_blank\" rel=\"noreferrer noopener\">Swift book<\/a> says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>&#8220;All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create\u2014and any value types they have as properties\u2014are always copied when they\u2019re passed around in your code.&#8221;<\/p><cite>&#8212; Swift Language Guide<\/cite><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">So whenever a node in the tree is modified, that results in copying the tree. When you change the tree by adding to it, the tree is copied. Using classes this does not happen. The excessive copying of the tree nodes is a performance killer when having very large data sets to handle. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is also a performance penalty in using classes &#8212; each time a class instance is accessed, the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/AutomaticReferenceCounting.html\" target=\"_blank\">retain \/<\/a><a href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/AutomaticReferenceCounting.html\" target=\"_blank\" rel=\"noreferrer noopener\"> <\/a><a rel=\"noreferrer noopener\" href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/AutomaticReferenceCounting.html\" target=\"_blank\">release count is updated<\/a>. But as you can see, still the implementation is much faster compared to copying the structure with value types.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Summarizing<\/strong>, enums are a nice way to implement recursive data structures. If you have large data sets and\/or the tree or tree nodes are updated often, consider using classes instead.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What if you need to define a tree like structure of data elements in Swift? For example you might use a Binary Search Tree to keep track of unique words in a book file: Since value types are often preferred in Swift, you could use a struct. The Node struct contains the word, the count &hellip; <a href=\"https:\/\/www.juustila.com\/antti\/2022\/01\/04\/swift-tree-structures-value-types-enums-and-classes\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Swift tree structures: value types, enums and classes&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[2],"tags":[48,74,60,39,46],"class_list":["post-850","post","type-post","status-publish","format-standard","hentry","category-coding","tag-algorithms","tag-binary-search-tree","tag-data-structures","tag-performance","tag-swift"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/comments?post=850"}],"version-history":[{"count":1,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/850\/revisions"}],"predecessor-version":[{"id":857,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/posts\/850\/revisions\/857"}],"wp:attachment":[{"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/media?parent=850"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/categories?post=850"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.juustila.com\/antti\/wp-json\/wp\/v2\/tags?post=850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}