<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="">Am 19.08.2017 um 20:33 schrieb Marc Schlichte via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>>:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi,<br class=""><br class="">to support cancellation, I propose the following changes to `beginAsync()` and `suspendAsync()`:<br class=""><br class="">`beginAsync()` returns an object adhering to a `Cancelable` protocol:<br class=""><br class="">```<br class="">func beginAsync(_ body: () async throws-> Void) rethrows -> Cancelable<br class=""><br class="">protocol Cancelable { func cancel() }<br class="">```<br class=""><br class="">`suspendAsync()` takes a new thunk parameter:<br class=""><br class="">```<br class="">func suspendAsync<T>(onCancel: () -> Void, body: (cont: (T) -> Void, err: (Error) -> Void) async -> T <br class="">```<br class=""><br class="">Now, when `cancel()` is invoked, the `onCancel` thunk in the current suspension (if any) will be called.</div></div></blockquote><blockquote type="cite" class=""><div class=""><div class=""><br class=""><br class="">Example:<br class=""><br class="">```<br class="">var task: Cancelable?<br class=""><br class="">@IBAction func buttonDidClick(sender: AnyObject) {<br class=""> task = beginAsync {<br class=""> do {<br class=""> let image = try await processImage()<br class=""> imageView.image = image <br class=""> } catch AsyncError.canceled {<br class=""> imageView.image = nil // or some fallback image...<br class=""> } catch {<br class=""> // other handling<br class=""> }<br class=""> } <br class="">)<br class=""><br class="">@IBAction func cancelDidClick(sender: AnyObject) {<br class=""> task?.cancel()<br class="">}<br class=""></div></div></blockquote><div><br class=""></div><div>Just adding here that instead of directly using the low-level `beginAsync`, a Future/Promise could be used instead:</div><div><br class=""></div><div>```</div><div>var task: Future<UIImage>?</div><div><br class=""></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 class=""></div><div>@iBAction func cancelDidClick(sender: AnyObject) {</div><div> task?.cancel()</div><div>}</div><div>```</div><div><br class=""></div><div>Of course, the init of Future would have to be changed</div><div><br class=""></div><div><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-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">convenience</span> <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">init</span>(<span class="pl-en" style="box-sizing: border-box; color: rgb(111, 66, 193);">_</span> <span class="pl-smi" style="box-sizing: border-box;">body</span>: () throws async <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">-></span> T) {
<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">self</span>.<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">init</span>()
task = beginAsync {
<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">do</span> {
<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">self</span>.<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">fulfill</span>(try await <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">body</span>())
} <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">catch</span> {
<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">self</span>.<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">fail</span>(error)
}
}
}</pre><div class="">(BTW also added missing throws and try in code above)</div><div class=""><br class=""></div><div class="">and `cancel()` would have to be added to `Future`:</div><div class=""><br class=""></div><div class="">```</div><div class="">public func cancel() {</div><div class=""> task?.cancel()</div><div class="">}</div><div class=""><br class=""></div><div class="">```</div></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class=""><br class="">func processImage() async throws -> UIImage {<br class=""> // This processing should be on a background queue (or better an Actor :-) - but ignored for this example<br class=""> var cancelled = false<br class=""> suspendAsync(onCancel: {<br class=""></div></div></blockquote></div><div><blockquote type="cite" class=""><div class=""><div class=""> cancelled = true<br class=""> }, body: { cont, err in<br class=""> while !done && !cancelled {<br class=""> // do the processing on image until done or canceled<br class=""> }<br class=""> guard !cancelled else { err(AsyncError.canceled) } // BTW, maybe change signature of `suspendAsync` to allow to throw here instead<br class=""> cont(image)<br class=""> }<br class="">}<br class="">```<br class=""></div></div></blockquote><div><br class=""></div>^ BTW, this should be `return await suspendAsync(…`<br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class="">Cheers<br class="">Marc<br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></div></blockquote></div><br class=""></body></html>