<div dir="ltr"><div>Hey All,<br></div><div><br></div><div>I want to share something I’ve been working on. I know this isn&#39;t strictly &quot;swift-evolution&quot; content, but I think it relates heavily to the ongoing conversation around concurrency features in the language (such as async/await).  If you&#39;re interested in such topics would you mind taking a look?</div><div><br></div><div><br></div><div><font face="monospace, monospace">HoneyBee.start { root in</font></div><div><font face="monospace, monospace">    root.setErrorHandler(handleError)</font></div><div><font face="monospace, monospace">        .chain(fetchNewMovieTitle)</font></div><div><font face="monospace, monospace">        .branch { stem in</font></div><div><font face="monospace, monospace">            stem.chain(fetchReviews)</font></div><div><font face="monospace, monospace">                .chain(averageReviews)</font></div><div><font face="monospace, monospace">            +</font></div><div><font face="monospace, monospace">            stem.chain(fetchComments)</font></div><div><font face="monospace, monospace">                .chain(countComments)</font></div><div><font face="monospace, monospace">        }</font></div><div><font face="monospace, monospace">        .setBlockPerformer(DispatchQueue.main)</font></div><div><font face="monospace, monospace">        .chain(updateUI)</font></div><div><font face="monospace, monospace">}</font></div><div><font face="monospace, monospace">func handleError(_ error: Error) {}</font></div><div><font face="monospace, monospace">func fetchNewMovieTitle(completion: (String?, Error?) -&gt; Void) {}</font></div><div><font face="monospace, monospace">func fetchReviews(for movieTitle: String, completion: (FailableResult&lt;[String]&gt;) -&gt; Void) {}</font></div><div><font face="monospace, monospace">func averageReviews(_ reviews: [String]) throws -&gt; Int { return reviews.count }</font></div><div><font face="monospace, monospace">func fetchComments(for movieTitle: String, completion: (([String]?, Error?) -&gt; Void)?) {}</font></div><div><font face="monospace, monospace">func countComments(_ comments: [String]) -&gt; Int { return comments.count }</font></div><div><font face="monospace, monospace">func updateUI(withAverageReview: Int, commentsCount: Int) {}</font></div><div><br></div><div><br></div><div>(Yes that compiles. Much thanks to the Language Team.)</div><div><br></div><div>HoneyBee makes concurrent programming expressive, easy and safe. The above recipe lexically matches the flow of execution. </div><div>First `fetchNewMovieTitle` is invoked. Then `fetchReviews` and `fetchComments` are invoked in parallel each receiving the result of `fetchNewMovieTitle`. `averageReviews` is invoked after `fetchReviews` finishes and `countComments` is invoked after `fetchComments`. The results of `averageReviews` and `countComments` are combined and forwarded to `updateUI`, which is invoked on the main queue.</div><div><br></div><div><br></div><div><font face="monospace, monospace">HoneyBee.start(on: DispatchQueue.main) { root in</font></div><div><font face="monospace, monospace">    root.setErrorHandler(handleError)</font></div><div><font face="monospace, monospace">        .chain(fetchNewMovieTitle)</font></div><div><font face="monospace, monospace">        .chain(fetchReviews)</font></div><div><font face="monospace, monospace">        .map { elem in // parallel map</font></div><div><font face="monospace, monospace">            elem.chain(\.count)    // Keypath access</font></div><div><font face="monospace, monospace">        }</font></div><div><font face="monospace, monospace">        .filter { elem in // parallel filtering</font></div><div><font face="monospace, monospace">            elem.chain(isNonTrivial)</font></div><div><font face="monospace, monospace">        }</font></div><div><font face="monospace, monospace">        .reduce { pair in // parallel &quot;pyramid&quot; reduce</font></div><div><font face="monospace, monospace">            pair.chain(+) // operator access</font></div><div><font face="monospace, monospace">        }</font></div><div><font face="monospace, monospace">        .chain(updateUI)</font></div><div><font face="monospace, monospace">}</font></div><div><font face="monospace, monospace">func handleError(_ error: Error) {}</font></div><div><font face="monospace, monospace">func fetchNewMovieTitle(completion: (String?, Error?) -&gt; Void) {}</font></div><div><font face="monospace, monospace">func fetchReviews(for movieTitle: String, completion: (FailableResult&lt;[String]&gt;) -&gt; Void) {}</font></div><div><font face="monospace, monospace">func isNonTrivial(_ int: Int, completion: (Bool) -&gt; Void) {}</font></div><div><font face="monospace, monospace">func updateUI(withTotalWordsInNonTrivialReviews: Int) {}</font></div><div><br></div><div><br></div><div>The above recipe demonstrates use of parallel map, filter and reduce. The entire recipe is run on the main queue. </div><div><br></div><div><br></div><div><font face="monospace, monospace">struct Image {}</font></div><div><font face="monospace, monospace">func processImageData(completionBlock: @escaping (Image?, Error?) -&gt; Void) {</font></div><div><font face="monospace, monospace">    func loadWebResource(named name: String, completion: (Data?, Error?) -&gt; Void) {}</font></div><div><font face="monospace, monospace">    func decodeImage(dataProfile: Data, image: Data) throws -&gt; Image { return Image() }</font></div><div><font face="monospace, monospace">    func dewarpAndCleanupImage(_ image: Image, completion: (Image?, Error?) -&gt; Void) {}</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">    HoneyBee.start { root in</font></div><div><font face="monospace, monospace">        root.setErrorHandler { completionBlock(nil, $0) }</font></div><div><font face="monospace, monospace">            .branch { stem -&gt; Link&lt;(Data,Data)&gt; in</font></div><div><font face="monospace, monospace">                stem.chain(loadWebResource =&lt;&lt; &quot;dataprofile.txt&quot;)</font></div><div><font face="monospace, monospace">                +</font></div><div><font face="monospace, monospace">                stem.chain(loadWebResource =&lt;&lt; &quot;imagedata.dat&quot;)</font></div><div><font face="monospace, monospace">            }</font></div><div><font face="monospace, monospace">            .chain(decodeImage)</font></div><div><font face="monospace, monospace">            .chain(dewarpAndCleanupImage)</font></div><div><font face="monospace, monospace">            .chain{ completionBlock($0, nil) }</font></div><div><font face="monospace, monospace">    }</font></div><div><font face="monospace, monospace">}</font></div><div><br></div><div>The above recipe is a translation of the now famous <a href="https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782">clatner &quot;pyramid of doom&quot;</a>. Note that the HoneyBee form allows us to effortlessly parallelize the two data fetches. </div><div><br></div><div><br></div><div>HoneyBee has many more features including:</div><div><br></div><div>* Total of 34 chain signatures</div><div>* Limit to globally control accesses to a resource</div><div>* Retry to re-attempt subchains that are known to have transient failures</div><div>* Helpful diagnostics when things go wrong</div><div><br></div><div>See the full documentation at <a href="http://HoneyBee.link">HoneyBee.link</a></div><div><br></div><div>Thanks for your time. Looking forward to your feedback,</div><div><br></div><div>Alex</div></div>