<div dir="ltr"><div>I dont like the idea of beginAsync, suspendAsync be a standard library functions to support a language level resource.</div><div><br></div><div>beginAsync can be only `async` and suspendAsync  can be &quot;await resync&quot; (something like that).</div><div><div><br></div><div>Saing that, cancel a operations is not that simple! Abrupt abort any thread can leave some consequences. Usually, for network code is ok, but some other multi-thread operations is not (like calculus, drawing, file operations, etc)</div></div><div><br></div><div>Timeout is not useful on mathematical operations, abort any thread which is accessing a physical device also can be dangerous (I broke one machine one time). There&#39;s no straight answer to &quot;how&quot; we can stop a execution block. Pause/Cancel when using a GCD queue is not that simple too! We need to remember that one of Swift&#39;s goals is to be a systems language. Not everything that is useful in &quot;high level&quot; is useful in &quot;low level&quot;.</div><div><br></div><div>Yes, coordination is important, but not a simple question to a run-time agnostic way to implement concurrency. Of course we can choose to make a run-time specific way to implement this, but i don&#39;t think is a valuable choice now.</div><div><br></div><div>But.... return something beginAsync, suspendAsync, ever a `bool` is a good ideia (the proposal cover that too).</div><br><div class="gmail_quote"><div dir="ltr">Em seg, 28 de ago de 2017 às 22:42, Howard Lovatt via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; escreveu:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">I think this makes the proposed async/await coroutines more viable. Building on this, if the proposed Cancelable became:<div><br></div><div>    protocol ExecutionControl {</div><div>        /// Causes the executing coroutine to throw `TerminateCoroutine.cancelled` and also terminates all the sub-coroutines.</div><div>        var isCancelled: Bool { set }</div><div><br></div><div>        /// If an await exceeds timeout then executing task throws `TerminateCoroutine.timeout` and also terminates all the sub-coroutines.</div><div>        var timeout: DispatchTimeInterval { get set }</div><div>    }<br></div><div><br></div><div>Then async/await coroutine would have feature parity with a typical `Future` - which would be good.</div><div><br></div><div>PS Effectively the execution service is returning the `Future`!</div></div><div class="gmail_extra"><br clear="all"><div><div class="m_-3889962939390953625m_-6878606713309630954gmail_signature" data-smartmail="gmail_signature">  -- Howard.<br></div></div></div><div class="gmail_extra">
<br><div class="gmail_quote">On 29 August 2017 at 09:42, Marc Schlichte via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><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>Am 19.08.2017 um 20:33 schrieb Marc Schlichte via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;:</div><br class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258Apple-interchange-newline"><div><div>Hi,<br><br>to support cancellation, I propose the following changes to `beginAsync()` and `suspendAsync()`:<br><br>`beginAsync()` returns an object adhering to a `Cancelable` protocol:<br><br>```<br>func beginAsync(_ body: () async throws-&gt; Void) rethrows -&gt; Cancelable<br><br>protocol Cancelable { func cancel() }<br>```<br><br>`suspendAsync()` takes a new thunk parameter:<br><br>```<br>func suspendAsync&lt;T&gt;(onCancel: () -&gt; Void, body: (cont: (T) -&gt; Void, err: (Error) -&gt; Void) async -&gt; T <br>```<br><br>Now, when `cancel()` is invoked, the `onCancel` thunk in the current suspension (if any) will be called.</div></div></blockquote><blockquote type="cite"><div><div><br><br>Example:<br><br>```<br>var task: Cancelable?<br><br>@IBAction func buttonDidClick(sender: AnyObject) {<br>  task = beginAsync {<br>    do {<br>      let image = try await processImage()<br>      imageView.image = image <br>    } catch AsyncError.canceled {<br>      imageView.image = nil // or some fallback image...<br>    } catch {<br>      // other handling<br>    }<br>  }  <br>)<br><br>@IBAction func cancelDidClick(sender: AnyObject) {<br>  task?.cancel()<br>}<br></div></div></blockquote><div><br></div><div>Just adding here that instead of directly using the low-level `beginAsync`, a Future/Promise could be used instead:</div><div><br></div><div>```</div><div>var task: Future&lt;UIImage&gt;?</div><div><br></div><div>@IBAction func buttonDidClick(sender: AnyObject) {</div><div>  task = Future {</div><div>    try await processImage()</div><div>  }</div><div>  do {</div><div>    imageView.image = try await task!.get()</div><div>  } catch AsyncError.canceled {</div><div>    imageView.image = nil // or some fallback image...</div><div>  } catch {</div><div>    // other handling</div><div>  }</div><div>}</div><div><br></div><div>@iBAction func cancelDidClick(sender: AnyObject) {</div><div>  task?.cancel()</div><div>}</div><div>```</div><div><br></div><div>Of course, the init of Future would have to be changed</div><div><br></div><div><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,&#39;Liberation Mono&#39;,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)">  <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">convenience</span> <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">init</span>(<span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-en" style="box-sizing:border-box;color:rgb(111,66,193)">_</span> <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-smi" style="box-sizing:border-box">body</span>: () throws async <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">-&gt;</span> T) {
    <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">self</span>.<span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">init</span>()
    task = beginAsync {
      <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">do</span> {
        <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">self</span>.<span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">fulfill</span>(try await <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">body</span>())
      } <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-k" style="box-sizing:border-box;color:rgb(215,58,73)">catch</span> {
        <span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">self</span>.<span class="m_-3889962939390953625m_-6878606713309630954m_-3432277472789290258pl-c1" style="box-sizing:border-box;color:rgb(0,92,197)">fail</span>(error)
      }
    }
  }</pre><div>(BTW also added missing throws and try in code above)</div><div><br></div><div>and `cancel()` would have to be added to `Future`:</div><div><br></div><div>```</div><div>public func cancel() {</div><div>  task?.cancel()</div><div>}</div><div><br></div><div>```</div></div><div><br></div><blockquote type="cite"><div><div><br>func processImage() async throws -&gt; UIImage {<br>  // This processing should be on a background queue (or better an Actor :-) - but ignored for this example<br>  var cancelled = false<br>  suspendAsync(onCancel: {<br></div></div></blockquote></div><div><blockquote type="cite"><div><div>   cancelled = true<br>  }, body: { cont, err in<br>     while !done &amp;&amp; !cancelled {<br>       // do the processing on image until done or canceled<br>     }<br>     guard !cancelled else { err(AsyncError.canceled) } // BTW, maybe change signature of `suspendAsync` to allow to throw here instead<br>     cont(image)<br>  }<br>}<br>```<br></div></div></blockquote><div><br></div>^ BTW, this should be `return  await suspendAsync(…`<br><blockquote type="cite"><div><div><br>Cheers<br>Marc<br><br>_______________________________________________<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" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></div></blockquote></div><br></div><br>_______________________________________________<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>
<br></blockquote></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></div>