<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="">I've read async/await proposal, and I'm thrilled by the possibilities. Here's what I consider the canonical example:<div class=""><pre class=""><code class="">@IBAction func buttonDidClick(sender:AnyObject) {
beginAsync {
let image = await processImage()
imageView.image = image
}
}</code></pre></div><div class="">This is exactly the kind of thing I will use async/await for!</div><div class=""><br class=""></div><div class="">But while this example looks extremely elegant, it would suffer from a number of problems in practice:</div><div class=""><br class=""></div><div class="">1. There is no guarantee that you are on the main thread after `await processImage()`<br class="">2. There is no way to cancel processing <br class="">3. Race Condition: If you click the button a second time before `processImage()` is done, two copies will run simultaneously and you don't know which image will "win".<br class=""><br class=""></div><div class="">So I wondered: What would a more thorough example look like in practice? How would I fix all these issues?</div><div class=""><br class=""></div><div class="">After some consideration, I came up with the following minimal example that addresses all these issues:</div><div class=""><pre class=""><code class="">class ImageProcessingTask {
var cancelled = false
func process() async -> Image? { … }
}
</code></pre><pre class=""><code class="">var currentTask: ImageProcessingTask?
@IBAction func buttonDidClick(sender:AnyObject) {
<div class=""> currentTask?.cancelled = true</div><div class=""> let task = ImageProcessingTask()</div><div class=""> currentTask = task</div> beginAsync {
guard let image = await task.process() else { return }
DispatchQueue.main.async {
guard task.cancelled == false else { return }
imageView.image = image
}
}
}</code></pre><div class="">If my example isn't obvious, I've documented my thinking (and some alternatives) in a gist:</div></div><div class=""><a href="https://gist.github.com/jakob/22c9725caac5125c1273ece93cc2e1e7" class="">https://gist.github.com/jakob/22c9725caac5125c1273ece93cc2e1e7</a></div><div class=""><br class=""></div><div class=""><div class="">Anyway, this more realistic code sample doesn't look nearly as nice any more, and I actually think this could be implemented nicer without async/await:</div></div><div class=""><br class=""></div><div class=""><div class=""><font face="monospace" class=""><span style="white-space: pre;" class="">class ImageProcessingTask {</span></font></div><div class=""><font face="monospace" class=""><span style="white-space: pre;" class=""> var cancelled = false</span></font></div><div class=""><font face="monospace" class=""><span style="white-space: pre;" class=""> func process(completionQueue: DispatchQueue, completionHandler: (Image?)->()) { … }</span></font></div><div class=""><font face="monospace" class=""><span style="white-space: pre;" class="">}</span></font></div><div class=""><font face="monospace" class=""><div class=""><span style="white-space: pre;" class="">@IBAction func buttonDidClick(sender:AnyObject) {</span></div><span style="white-space: pre;" class=""> currentTask?.cancelled = true<br class=""> let task = ImageProcessingTask()<br class=""></span><div class=""><span style="white-space: pre;" class=""> currentTask = task</span></div><div class=""><span style="white-space: pre;" class=""> task.process(</span><span style="white-space: pre;" class="">completionQueue: </span><span style="white-space: pre;" class="">DispatchQueue.main</span><span style="white-space: pre;" class="">) { (image) in</span></div></font><font face="monospace" class=""><span style="white-space: pre;" class=""> guard let </span></font><span style="font-family: monospace; white-space: pre;" class="">image = </span><span style="font-family: monospace; white-space: pre;" class="">image else { return }</span></div><div class=""><span style="font-family: monospace; white-space: pre;" class=""> guard task.cancelled == false else { return }</span></div><div class=""><font face="monospace" class=""><span style="white-space: pre;" class=""> </span></font><span style="font-family: monospace; white-space: pre;" class="">imageView.image = image</span><font face="monospace" class=""><span style="white-space: pre;" class=""><br class=""> }<br class=""></span><div class=""><span style="white-space: pre;" class="">}</span></div><span style="white-space: pre;" class=""><br class=""></span></font><div class="">So I wonder: What's the point of async/await if it doesn't result in nicer code in practice? How can we make async/await more elegant when calling from non-async functions?</div></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jakob</div><div class=""><br class=""></div></body></html>