Here's a idea:
-
No need to spell
await
at the end of a function scope. The function isasync
so there's anawait
in the caller at the call boundary. Thisawait
in the caller can cover our implicit await at the end of the function scope, as long as the implicit await is done after anydefer
block in the function. -
Don't await (even implicitly) when exiting most scopes (
if
,switch
,try
,catch
...). Those awaits are pushed at the end of the function scope. There's little to be gained by implicitly awaiting at every scope, and it's better to reduce the number of suspension points. -
An explicit await is required for loop scopes. You can use
await break
orawait continue
when there is anasync let
that needs to be awaited. The compiler will have a fixit for you if you forget.- You can still exit a loop with a simple
return
with noawait
. As long as it gets merged with the the function scope implicit await it's fine.
- You can still exit a loop with a simple
This way we reduce the number of suspension points and all the suspension points remain explicitly spelled with await
. Maybe it makes things slightly less structured, but I think it's for the better.
Example:
func test() async {
async let x = work(0)
if condition {
async let y = work(1)
}
for i in 2..<10 {
async let z = work(i)
if condition {
return // implicitly awaits x, y, z
}
if condition {
await break // awaits z
}
await continue // required here, awaits z
}
// implicitly awaits x, y
}