tcldr
1
Currently, when a function has an '@autoclosure` attributed closure parameter, that closure is constrained to being synchronous.
func a(_ f: @autoclosure @escaping () async -> Int) {}
// ERROR: 'async' autoclosure parameter in a non-'async' function
This means that if you wish to express that a closure parameter may auto-close, but should also optionally accept an async closure parameter you have to overload the function:
func a(_ f: @autoclosure @escaping () -> Int) {}
func a(_ f: @escaping () async -> Int) {}
Is there any reason we shouldn't make this the default behaviour of @autoclosure. i.e. if the parameter has been 'auto-closed', assume the supplied closure is synchronous?
The only reason I can think that this would be a problem is if an asynchronous expression is evaluated at the call-site a(await getFunc()), but theoretically the complier would ultimately handle this in the same way as it handles the overloaded example above.
cukr
2
Hi! Note that the @autoclosure always auto-closes, even without the async. If you try to pass in a closure directly, it will give you an error:
func b(_ f: @autoclosure () -> Int) { }
let closure: () -> Int = { 5 }
b(closure) // error: Add () to forward @autoclosure parameter
Why? It would add complexity to the language, and make things ambiguous
func c(_ f: @autoclosure () -> Any) {
print(type(of: f()))
}
let closure: () -> Int = { 5 }
c(closure) // should it print "() -> Int" or "Int" ?
// Currently it prints "() -> Int", but without auto-closing it would print "Int" instead
The solution is simple, and you already discovered it: overload the function.
1 Like
tcldr
3
Got it. OK, thank you. That makes a lot of sense. Clearly, I'm a bit late to the @autoclosure party 
1 Like