[swift-evolution] [Concurrency] Async/Await

Brent Royal-Gordon brent at architechies.com
Tue Aug 22 18:19:39 CDT 2017

> On Aug 22, 2017, at 9:32 AM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
>>> async as a subtype of throws instead of orthogonal to it
>>> I’ve been thinking a lot about this since the proposal came out and I see a few serious disadvantages at making async a subtype of throws which might benefit from being discussed or/and mentioned in the proposal.
>>> 1. We loose the automatic documentation try provides for signaling failable functions:
>>> let image = await downloadImage()
>>> let processedImage = await processImage(image)
>>> await present(MyViewController(image: image))
>>> In my example, downloadImage can fail because of network conditions, processImage can not fail, and present 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.
> 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.

You may be able to handle cancellation by abandoning the completion, rather than returning an error. And I can't imagine the error behavior of a low-level operation like `processImage(_:)` would ever bubble back up into the UI, so you can incorporate that error logic into the async function. (For instance, if you want to do the operation on the GPU but fall back to the CPU if it fails, then do that fallback inside `processImage(_:)`.)

And if I'm wrong? Well, then you'll add `throws` and the compiler will tell you where to insert error handling. The switch from "zero errors" to "some errors" is much simpler than the switch from "N errors" to "N+1 errors". And remember, if the code previously couldn't throw in practice, any error handling code the user might have written to placate the compiler has probably never been exercised. There's a pretty good chance they used `try!` or empty `catch` blocks to quickly dispose of the non-existent errors. The compiler can tell you where you need to add error-handling code, but it can't tell you where your error-handling code is useless or wrong.

> 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.

The `UIViewController.present` method has a completion block; I assume David Hart is thinking that `await` here would cause the subsequent code to run once the view controller finished presenting.

(Which brings up an interesting point: there are some APIs with completion blocks that you only occasionally use. For these APIs, it might make sense to have an `ignore` counterpart to `await` or something, and that counterpart seems like it might make `beginAsync` redundant.)

Brent Royal-Gordon

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170822/a044569c/attachment.html>

More information about the swift-evolution mailing list