> On Aug 22, 2017, at 9:32 AM, Joe Groff via swift-evolution 
> <[email protected]> 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
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to