{"id":2868,"date":"2014-06-26T10:59:20","date_gmt":"2014-06-26T13:59:20","guid":{"rendered":"http:\/\/brockerhoff.net\/blog\/?p=2868"},"modified":"2014-07-07T22:51:42","modified_gmt":"2014-07-08T01:51:42","slug":"swift-a-simple-future","status":"publish","type":"post","link":"https:\/\/brockerhoff.net\/blog\/2014\/06\/26\/swift-a-simple-future\/","title":{"rendered":"Swift: a simple Future"},"content":{"rendered":"<p>While doing research for my next Swift article, I implemented a very simple future class, which might be of interest:<\/p>\n<pre><code>import Foundation\r\n\r\nfunc PerformOnMain(work: () -&gt; Void) {\r\n\tCFRunLoopPerformBlock(NSRunLoop.mainRunLoop().getCFRunLoop(), kCFRunLoopCommonModes, work)\r\n}\r\n\r\nfunc PerformAsync(work: () -&gt; Void) {\r\n\tdispatch_async(dispatch_get_global_queue(0, 0), work)\r\n}\r\n\r\nclass Future &lt;T&gt; {\r\n\tlet lock = NSCondition()\r\n\tvar result: [T] = []\r\n\t\r\n\tfunc _run(work: () -&gt; T) {\r\n\t\tPerformAsync {\r\n\t\t\tlet value = work()\r\n\t\t\tself.lock.lock()\r\n\t\t\tself.result = [ value ]\r\n\t\t\tself.lock.broadcast()\r\n\t\t\tself.lock.unlock()\r\n\t\t}\r\n\t}\r\n\t\r\n\tinit(work: () -&gt; T) {\r\n\t\t_run(work)\r\n\t}\r\n\t\r\n\tinit(_ work: @auto_closure ()-&gt; T) {\r\n\t\t_run(work)\r\n\t}\r\n\t\r\n\tvar value: T {\r\n\t\tlock.lock()\r\n\t\twhile result.isEmpty {\r\n\t\t\tlock.wait()\r\n\t\t}\r\n\t\tlet r = result[0]\r\n\t\tlock.unlock()\r\n\t\treturn r\r\n\t}\r\n}<\/code><\/pre>\n<p>It&#8217;s used as follows:<\/p>\n<pre><code>let futureString: Future&lt;String?&gt; = Future {\r\n\t\/\/ ... protracted action that may return a string\r\n\treturn didItWork ? aString : nil\r\n}\r\n\r\n\/\/ alternatively, if you just have a function call or expression:\r\nlet anotherString: Future&lt;String&gt; = Future(SomeFunctionThatTakesALongTime())\r\n\/\/ ... do other things, then when you need the future's value:\r\nlet theString = futureString.value<\/code><\/pre>\n<p>In other words, the closure will be executed asynchronously, then when you need the result,\u00a0getting <code>value<\/code> will block until it&#8217;s ready. The result of the closure can be of any type and even (as in the first example) be optional (that is, may be\u00a0<code>nil<\/code>). Once the result is ready, getting <code>value<\/code> will not block.<\/p>\n<p>My interest in futures began with <a href=\"https:\/\/www.mikeash.com\/pyblog\/friday-qa-2010-02-26-futures.html\" target=\"_blank\">Mike Ash&#8217;s excellent article<\/a> about an <a href=\"https:\/\/github.com\/mikeash\/MAFuture\" target=\"_blank\">Objective-C implementation<\/a>\u00a0of the concept. Mike&#8217;s implementation (<code>MAFuture<\/code>) is of an implicit future; that is, it returns a proxy object which transparently stands in for the future value and doesn&#8217;t block when operations like <code>retain\/release<\/code> are performed; therefore, you can add the future to an <code>NSArray<\/code> or <code>NSDictionary<\/code> while it&#8217;s still being computed. The downside is that, because of the intricacies of message forwarding in Objective-C, the future can&#8217;t return a nil value.<\/p>\n<p><code>MAFuture<\/code>\u00a0has grown to be rather complex, now catering to iOS memory triggers, archiving and whatnot, so I made a very bare-bones variation for my own projects, where it has been very useful.<\/p>\n<p>Swift has no proxy objects (yet?), so implicit futures can&#8217;t be done; I tried to code the proxy in Objective-C and subclass in Swift, but ran into too many compiler\/runtime bugs \u2014 it&#8217;s a beta, after all. However, the explicit implementation above has the advantage that the future can return any Swift type, including optional.<\/p>\n<p>An additional <code>Future<\/code>\u00a0property that might be useful in some places:<\/p>\n<pre><code>var resolved: Bool {\r\n\tlock.lock()\r\n\tlet r = !result.isEmpty\r\n\tlock.unlock()\r\n\treturn r\r\n}<\/code><\/pre>\n<p>you can use this to test if the result is available without blocking.<\/p>\n<p>There are more complex futures available already. I looked at <a href=\"https:\/\/github.com\/maxpow4h\/swiftz\" target=\"_blank\">Swiftz<\/a> (by Maxwell Swadling) and <a href=\"https:\/\/github.com\/Thomvis\/BrightFutures\" target=\"_blank\">BrightFutures<\/a> (by Thomas Visser), which also implement other constructs. If you have a functional programming background you should examine them, too.<\/p>\n<p><strong>Update:<\/strong> Mike Ash suggested a small change in my code above (have to <code>broadcast<\/code> before <code>unlock<\/code>), and confirmed that everything should work properly. Thanks Mike!<\/p>\n<p><strong>Update#2:<\/strong>\u00a0some more small changes, added the autoclosure form and a <code>PerformOnMain<\/code> function that fills in for the Objective-C <code>performSelectorOnMainThread:<\/code> method &#8211; useful for updating UI at the conclusion of a future&#8217;s closure.<\/p>\n<p><strong>Update#3:<\/strong> final form, in line with the <a href=\"https:\/\/github.com\/rbrockerhoff\/SwiftChecker\" target=\"_blank\">published sample app on github<\/a>. There are <a href=\"https:\/\/github.com\/rbrockerhoff\/SwiftChecker\/blob\/master\/SwiftChecker\/Future.swift\" target=\"_blank\">extensive comments<\/a> on details.<\/p>\n<p><strong>Update#4:\u00a0<\/strong>slight change for the new Array declaration syntax in Xcode 6.0b3.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>While doing research for my next Swift article, I implemented a very simple future class, which might be of interest: import Foundation func PerformOnMain(work: () -&gt; Void) { CFRunLoopPerformBlock(NSRunLoop.mainRunLoop().getCFRunLoop(), kCFRunLoopCommonModes, work) } func PerformAsync(work: () -&gt; Void) { dispatch_async(dispatch_get_global_queue(0, 0), work) } class Future &lt;T&gt; { let lock = NSCondition() var result: [T] = [] [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_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":""},"categories":[3,4,19],"tags":[47],"class_list":["post-2868","post","type-post","status-publish","format-standard","hentry","category-apple","category-dev","category-software","tag-swift"],"featured_image_src":null,"author_info":{"display_name":"Rainer Brockerhoff","author_link":"https:\/\/brockerhoff.net\/blog\/author\/rbrockerhoff\/"},"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1q3Zc-Kg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/posts\/2868","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/comments?post=2868"}],"version-history":[{"count":0,"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/posts\/2868\/revisions"}],"wp:attachment":[{"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/media?parent=2868"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/categories?post=2868"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brockerhoff.net\/blog\/wp-json\/wp\/v2\/tags?post=2868"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}