This proposal is really awesome, I'm very much looking forward to this!
Some random thoughts:
-
The proposal to force ordering of
async
beforethrows
is interesting - I don't think we have any precedent for this. I am not opposed to it, just making an observation. Are you force the same thing on the expression side, rejectingtry await foo()
? It seems like it should be consistent. -
I agree with the comment by @Jay-Madden that it would be good to consider what a naming convention would look like here. Something should be added to the API design guidelines about async.
-
I don't understand how the overloading rules will work. The existing
try
marker doesn't influence type checking (it is verified after the expression is checked), so this is deviating from its design. There are also ambiguous cases, given that theawait
marker covers a whole subexpression, for example inawait (x() + y())
if bothx
andy
have both overloads, then either could be picked. I suppose the rule is to pick a maximally awaiting version of this? How does this work if the overloads return different types etc? This seems like it will just make the type checker a lot more complicated.
Async/await are new features, so I don't see any reason why Swift programmers would want to write overloads like this (just like they don't/can't write overloads of throwing functions). I think this issue is limited to the Clang Importer for the ObjC feature, and that. can be handled by adding anAsync
suffix to the imported method (potentially iff there is a conflict). I would recommend going that way so the core language stays simpler and there is less pressure on the already complicated type system. -
Relating to the above, there is clearly a subtype relationship between async and sync functions of the same type. The rationale in the discussion about function types trying to explain why there are no implicit conversions doesn't make much sense to me.
-
Closure expressions have a "lot" of sugar (citation needed), and I think it is important for this to work consistently with
throws
in closure expressions. Should we allow{ async in ...}
as sugar for "infer the signature, but make it async"? I'm not actually sure if that works withthrows
closures - I sort of hope not :-) -
You will either want closure expression to infer their async'ness from callers, just like they infer their
@escaping
marker, or you will want subtyping between async and non-async functions, so that things like this work:functionThatTakesAnAsyncClosure { $0+1}
. The closure implementation doesn't "need" async, but needs to be compatible with a function argument declared as async. -
I agree that taking
await
as a keyword is the right way to go.
This proposal is super awesome, thank you for driving this forward. My concerns about the subtyping and overload resolution issues here are my most important. concerns. I would love to know if you've thought about other alternatives here that would make this more consistent with how try
and throws
works in the language.
Specific question for you: what does the Clang importer do today when you have an objc method that takes an NSError (importing as throws
) and another one that does not? A naive import would turn them into a redefinition, does one get renamed? If so, can we do the same thing for completion handlers? Did you consider just "not" importing them in this case? None of these auto-imported things are required for compatibility anyway, they are a new thing.
-Chris