<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 21, 2017, at 10:21 PM, David Hart <<a href="mailto:david@hartbit.com" class="">david@hartbit.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Sorry for the shameless bump :-/ but I’d love to get some answers so I can better understand the proposal and participate in the discussions.<div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 21 Aug 2017, at 07:58, David Hart via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hello,<div class=""><br class=""></div><div class="">Thanks for the great work on the async/await proposal! After reading it, I have a few questions and comments about it, so I’m creating this thread to concentrate on that topic (instead of Actors).</div><div class=""><br class=""></div><div style="font-size: 15px;" class=""><b class="">Generators</b></div><div class=""><br class=""></div><div class="">The proposal mentions in <b class="">Problem 6</b> of the <b class="">Motivation</b> how generators can help write sequences:</div><div class=""><br class=""></div><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">In contrast, languages that have generators allow you to write something more close to this:</p><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;" class=""><span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">func</span> <span class="pl-en" style="box-sizing: border-box; color: rgb(111, 66, 193);">getSequence</span>() <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">-></span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">AnySequence</span><<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">Int</span>> {
<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">let</span> seq <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">=</span> sequence {
<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">for</span> i <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">in</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">1</span><span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">...</span><span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">10</span> {
<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">yield</span>(i<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">*</span>i)
}
}
<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">return</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">AnySequence</span>(seq)
}</pre></div><div class=""><br class=""></div><div class="">This feels very similar to me from C# where the <font face="Menlo" class="">yield</font> keyword is used to support the generator feature. But I fail to see how the coroutines as described in this proposal resolve this problem. Can someone explain?</div></div></div></blockquote></div></div></div></div></blockquote><div><br class=""></div><div>The feature provides general delimited continuations. You could write an IteratorProtocol-conforming interface over a coroutine like this:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div>class Generator<T>: IteratorProtocol {</div></div><div><div> var next: T? = nil</div></div><div><div> var resume: (() -> ())? = nil</div></div><div><div><br class=""></div></div><div><div> init(_ body: (_ yield: @escaping (T) async -> Void) -> Void) {</div></div><div><div> self.resume = {</div></div><div><div> beginAsync {</div></div><div><div> body(self.yield)</div></div><div><div> }</div></div><div><div> }</div></div><div><div><br class=""></div></div><div><div> func next() -> T? {</div></div><div><div> if let resume = self.resume {</div></div><div><div> resume()</div></div><div><div> return self.next</div></div><div><div> }</div></div><div><div> return nil</div></div><div><div> }</div></div><div><div><br class=""></div></div><div><div> private func yield(_ value: T) async -> Void {</div></div><div><div> self.next = value</div></div><div><div> await suspendAsync { cont in</div></div><div><div> resume = cont</div></div><div><div> }</div></div><div><div> }</div></div><div><div>}</div></div><div><div><br class=""></div></div><div><div>let fibs = Generator { yield in</div></div><div><div> var (a, b) = (0, 1)</div></div><div><div> while a < 1000 {</div></div><div><div> await yield(a)</div></div><div><div> (a, b) = (b, a + b)</div></div><div><div> }</div></div><div><div>}</div></div></blockquote><div><br class=""></div><div>This isn't ideal in a number of ways (awkward, not particularly efficient, and has the gotcha that the generator's `body` could suspend itself with something other than the `yield` operation, doesn't integrate with ownership in the way John proposes in the ownership manifesto), so it may not be a good idea, of course.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="font-size: 15px;" class=""><b class="">beginAsync</b></div><div class=""><br class=""></div><div class="">The documentation of the <font face="Menlo" class="">beginAsync</font> and <font face="Menlo" class="">suspendAsync</font> functions state:</div><div class=""><br class=""></div><div class=""><pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; color: rgb(36, 41, 46);" class=""><span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);">// NB: Names subject to bikeshedding. These are low-level primitives that most</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> users should not need to interact with directly, so namespacing them</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> and/or giving them verbose names unlikely to collide or pollute code</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> completion (and possibly not even exposing them outside the stdlib to begin</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> with) would be a good idea.</span></pre><div class=""><br class=""></div></div><div class="">But I don’t understand how they can be kept private to the standard library when they are used for the important pattern of spawning off an async operation from a non-async function:</div></div></div></blockquote></div></div></div></div></blockquote><div><br class=""></div><div>beginAsync provides raw material for starting an async process, but I think you'd often want to wrap it up in something more interesting, like a DispatchQueue method that enqueues the coroutine on a specific queue, a Future constructor that captures the eventual result, etc. Nonetheless, I removed this statement from the proposal.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">Despite these problems, it is essential that the model encompasses this pattern, because it is a practical necessity in Cocoa development. With this proposal, it would look like this:</p><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.600000381469727px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;" class=""><span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">@IBAction</span> <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">func</span> <span class="pl-en" style="box-sizing: border-box; color: rgb(111, 66, 193);">buttonDidClick</span>(<span class="pl-smi" style="box-sizing: border-box;"><span class="pl-en" style="box-sizing: border-box; color: rgb(111, 66, 193);">sender</span></span>:<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">AnyObject</span>) {
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> 1</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"></span> beginAsync {
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> 2</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"></span> <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">let</span> image <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">=</span> await <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">processImage</span>()
imageView.<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">image</span> <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">=</span> image
}
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> 3</span></pre></div><div style="font-size: 15px;" class=""><b class="">Futures</b></div></div><div class=""><br class=""></div><div class="">When discussing futures, the proposal states:</div><div class=""><br class=""></div><div class=""><span style="color: rgb(36, 41, 46); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);" class="">The exact design for a future type deserves its own proposal, but a proof of concept could look like this:</span></div><div class=""><span style="color: rgb(36, 41, 46); background-color: rgb(255, 255, 255);" class=""><br class=""></span></div><div class=""><span style="background-color: rgb(255, 255, 255);" class=""><font color="#24292e" class="">Does that sentence imply that the Core Team would welcome a Future implementation into the Standard Library?</font></span></div></div></div></blockquote></div></div></div></div></blockquote><div><br class=""></div><div>It's worth discussing. My personal feeling is that a lot of the things people do with futures can potentially be done better with other coordination primitives, but we'll see.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div style="font-size: 15px;" class=""><span style="background-color: rgb(255, 255, 255);" class=""><font color="#24292e" class=""><b class="">async as a subtype of throws instead of orthogonal to it</b></font></span></div><div class=""><span style="background-color: rgb(255, 255, 255);" class=""><font color="#24292e" class=""><br class=""></font></span></div><div class=""><span style="background-color: rgb(255, 255, 255);" class=""><font color="#24292e" class="">I’ve been thinking a lot about this since the proposal came out and I see a few serious </font></span><font color="#24292e" class="">disadvantages at making async a subtype of throws which might benefit from being discussed or/and mentioned in the proposal.</font></div><div class=""><font color="#24292e" class=""><br class=""></font></div><div class=""><font color="#24292e" class="">1. We loose the automatic documentation <font face="Menlo" class="">try</font> provides for signaling failable functions:</font></div><div class=""><br class=""></div><div class=""><font color="#24292e" face="Menlo" class="">let image = await downloadImage()</font></div><div class=""><font color="#24292e" face="Menlo" class="">let processedImage = await processImage(image)</font></div><div class=""><font color="#24292e" face="Menlo" class="">await present(MyViewController(image: image))</font></div><div class=""><font color="#24292e" class=""><br class=""></font></div><div class=""><font color="#24292e" class="">In my example, <font face="Menlo" class="">downloadImage</font> can fail because of network conditions, <font face="Menlo" class="">processImage</font> can not fail, and <font face="Menlo" class="">present</font> is the UIKit function which presents view controllers and it can’t fail either. But that’s not obvious from reading the code. We’ve lost information.</font></div></div></div></blockquote></div></div></div></div></blockquote><div><br class=""></div><div>This seems like a similar pitfall to too narrow exception types that we try to avoid with `throws`. Saying that even a long-lived computation like processImage can't throw is a brittle architectural choice, since you may need to build in support for cancellation at some point, and if you ever decide to offload the computation to a GPU, coprocessor, or out-of-process worker, then it will be able to fail at that point. It's not clear to me why `present` would be async here; it seems to me like a fire-and-forget kind of operation you don't want to wait for.</div></div><br class=""><div class="">-Joe</div></body></html>