<div dir="rtl"><div dir="ltr">I think that the solution you are describing is how RxSwift (ReactiveX) solves this problem. </div><div dir="ltr"><br></div><div dir="ltr">I believe Rx, like many other higher level abstractions would benefit from async, actors behind the scenes, as an implementation detail.</div></div><br><div class="gmail_quote"><div dir="rtl">‫בתאריך יום ד׳, 23 באוג׳ 2017 ב-20:41 מאת ‪Joe Groff via swift-evolution‬‏ &lt;‪<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>‬‏&gt;:‬<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><blockquote type="cite"><div>On Aug 19, 2017, at 4:56 AM, Jakob Egger via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_-1773459520748767038Apple-interchange-newline"><div><div style="word-wrap:break-word">I&#39;ve read async/await proposal, and I&#39;m thrilled by the possibilities. Here&#39;s what I consider the canonical example:<div><pre><code>@IBAction func buttonDidClick(sender:AnyObject) {
  beginAsync {
    let image = await processImage()
    imageView.image = image
  }
}</code></pre></div><div>This is exactly the kind of thing I will use async/await for!</div><div><br></div><div>But while this example looks extremely elegant, it would suffer from a number of problems in practice:</div><div><br></div><div>1. There is no guarantee that you are on the main thread after `await processImage()`<br>2. There is no way to cancel processing <br>3. Race Condition: If you click the button a second time before `processImage()` is done, two copies will run simultaneously and you don&#39;t know which image will &quot;win&quot;.<br><br></div><div>So I wondered: What would a more thorough example look like in practice? How would I fix all these issues?</div><div><br></div><div>After some consideration, I came up with the following minimal example that addresses all these issues:</div><div><pre><code>class ImageProcessingTask {
  var cancelled = false
  func process() async -&gt; Image? { … }
}
</code></pre><pre><code>var currentTask: ImageProcessingTask?
@IBAction func buttonDidClick(sender:AnyObject) {
<div>  currentTask?.cancelled = true</div><div>  let task = ImageProcessingTask()</div><div>  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>If my example isn&#39;t obvious, I&#39;ve documented my thinking (and some alternatives) in a gist:</div></div><div><a href="https://gist.github.com/jakob/22c9725caac5125c1273ece93cc2e1e7" target="_blank">https://gist.github.com/jakob/22c9725caac5125c1273ece93cc2e1e7</a></div><div><br></div><div><div>Anyway, this more realistic code sample doesn&#39;t look nearly as nice any more, and I actually think this could be implemented nicer without async/await:</div></div><div><br></div><div><div><font face="monospace"><span style="white-space:pre-wrap">class ImageProcessingTask {</span></font></div><div><font face="monospace"><span style="white-space:pre-wrap">  var cancelled = false</span></font></div><div><font face="monospace"><span style="white-space:pre-wrap">  func process(completionQueue: DispatchQueue, completionHandler: (Image?)-&gt;()) { … }</span></font></div><div><font face="monospace"><span style="white-space:pre-wrap">}</span></font></div><div><font face="monospace"><div><span style="white-space:pre-wrap">@IBAction func buttonDidClick(sender:AnyObject) {</span></div><span style="white-space:pre-wrap">  currentTask?.cancelled = true<br>  let task = ImageProcessingTask()<br></span><div><span style="white-space:pre-wrap">  currentTask = task</span></div><div><span style="white-space:pre-wrap">  task.process(</span><span style="white-space:pre-wrap">completionQueue: </span><span style="white-space:pre-wrap">DispatchQueue.main</span><span style="white-space:pre-wrap">) { (image) in</span></div></font><font face="monospace"><span style="white-space:pre-wrap">    guard let </span></font><span style="font-family:monospace;white-space:pre-wrap">image = </span><span style="font-family:monospace;white-space:pre-wrap">image else { return }</span></div><div><span style="font-family:monospace;white-space:pre-wrap">    guard task.cancelled == false else { return }</span></div><div><font face="monospace"><span style="white-space:pre-wrap">    </span></font><span style="font-family:monospace;white-space:pre-wrap">imageView.image = image</span><font face="monospace"><span style="white-space:pre-wrap"><br>  }<br></span><div><span style="white-space:pre-wrap">}</span></div><span style="white-space:pre-wrap"><br></span></font><div>So I wonder: What&#39;s the point of async/await if it doesn&#39;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></div></blockquote><br></div></div><div style="word-wrap:break-word"><div>Yeah, it&#39;s important to understand that coroutines don&#39;t directly offer any form of coordination; they only let you thread execution nicely through existing coordination mechanisms. IBActions by themselves don&#39;t offer any coordination, so anything more than fire-and-forget is still going to require explicit code. There are some interesting approaches you still might be able to explore to make this kind of thing nicer; for instance, if buttonDidClick didn&#39;t directly trigger the task, but instead communicated with a coroutine via synchronous channels in the style of Go, then that coroutine could be responsible for filtering multiple click events, and could also listen for cancellation events. The actor model Chris proposes in his document could conceivably let you wrap up that low-level channel management in a nice OO-looking wrapper.</div></div><div style="word-wrap:break-word"><div><br></div><div>-Joe</div><br></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>