[swift-evolution] await keyword "scope"

Wallacy wallacyf at gmail.com
Tue Sep 12 15:00:19 CDT 2017


Em ter, 12 de set de 2017 às 16:48, Adam Kemp via swift-evolution <
swift-evolution at swift.org> escreveu:

>
> I think that decision makes sense for try/throws, but I feel like the
> await keyword is fundamentally different from that. The pitfalls of not
> understanding how the code is transformed and how it will behave at runtime
> are much greater with await than with try.
>
> If you have a line of code with multiple expressions that can throw then
> the consequences of not knowing which particular one threw the error are
> minor. In most cases it doesn’t matter, and you would handle a given error
> the same regardless of which subexpression threw the error.
>
> With await the function is actually broken up into pieces, and unrelated
> code can run in between those pieces on the same thread and/or the same
> queue. That has a much higher potential of leading to subtle bugs if you
> can’t see where those breaks are.
>
>
> What sort of bugs?  Can you please provide a concrete example we can
> discuss?
>
>
> Here’s just a simple example of code that looks right but is buggy:
>
> @IBAction func buttonDidClick(sender:AnyObject) {
>     beginAsync {
>         let image = await processImage(downloadImage(), resize:
> self.resizeSwitch.isOn)
>         displayImage(image)
>     }
> }
>
>
> That code I believe would be equivalent to this more explicit code:
>
> @IBAction func buttonDidClick(sender:AnyObject) {
>     beginAsync {
>         let downloadedImage = await downloadImage()
>         let resizeSwitchIsOn = self.resizeSwitch.isOn
>         let image = await processImage(downloadedImage,
> resize: resizeSwitchIsOn)
>         displayImage(image)
>     }
> }
>
>
> The subtlety here is that control can be returned to the run loop before
> the code checks the value of resizeSwitch.isOn. That means there is a time
> when the user can change the switch before it’s read.
>
>
Obviously someone could write the second version of this code and have the
> same bug so the problem isn’t that it’s possible to write this bug. The
> problem is that it’s not clear in the first example where those breaks are
> where control may be returned to the run loop. Someone reading the first
> example can’t tell when self.resizeSwitch.isOn is going to be read (now or
> some future iteration of the run loop).
>
>
So, the problem is a predefined order to evaluate the values, not a
"second" await.

Like you said, the person can write the wrong code ever anyway!


> The correct way to write this would be to read the UI up front:
>
> @IBAction func buttonDidClick(sender:AnyObject) {
>     beginAsync {
>         let resizeSwitchIsOn = self.resizeSwitch.isOn
>         let downloadedImage = await downloadImage()
>         let image = await processImage(downloadedImage,
> resize: resizeSwitchIsOn)
>         displayImage(image)
>     }
> }
>
>
>
In this case is not better discuss the precedence order to evaluate the
values?


> Based on my experience dealing with async/await code and the subtlety of
> returning to the run loop in between expressions I think the added clarity
> of an explicit await for each call outweighs the inconvenience. It is a
> hard enough adjustment for people to understand that this function executes
> in pieces with other code running in between. I think it would be an even
> harder adjustment if you couldn’t use a simple rule like “every time you
> see await there is a break right there”. In the original example there are
> two breaks in the same line, and it’s opaque to the reader where those
> breaks are.
>
>
Precedence order still be a problem using another "await" keyword.


> This example also shows once again the importance of returning to the
> right queue. If the “await downloadImage” continues on some other queue
> then you would be using UIKit on a background thread, which is not allowed.
> It seems like we’re starting to see some convergence on this idea, which
> I’m glad to see.
>


The proposal already covered this:

  await DispatchQueue.main.syncCoroutine()


Maybe not the best way, but this is one possible way.



> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170912/1427df1b/attachment.html>


More information about the swift-evolution mailing list