Indeed, having an async
keyword is technically unnecessary. This would also avoid issues such as the what color is your function? problem.
But it's not without cost. There might be a cost in performance, and a cost in clarity.
Async code implies a very different execution model from synchronous code. In some languages, this is closely coupled with multithreading so just eliding async would have little consequence. But in many languages, an async
function is transformed by the compiler into a state machine that can be suspended and resumed. Such a state machine would have unnecessary overhead for ordinary synchronous code. Callers of such functions would also have to start to await every return value.
Your suggestion to automatically make functions async if they contain an await is feasible. Similarly, Python turns a function into a generator if it contains a yield
. But changing the type and execution model of a function depending on the implementation details of the function would not make it easy to understand the code.
In practice, the async keyword as used by Rust of C# does the following.
We take a function like this:
async T DoSomething() { ... }
The compiler transforms this into the equivalent definition
Task<T> DoSomething() { new StateMachine { ... } }
With your suggestion of an implicit async we wouldn't be able to tell if a declaration T DoSomething() { ... }
actually has the type T DoSomething()
or if it has type Task<T> DoSomething()
. The everything-is-async approach would always result in the latter, but as mentioned this would have extra runtime overhead and extra awaits.
So in my opinion, sticking with an async
keyword is perfectly fine. However, I would like it if future languages make it easier to abstract over async and non-async code, for example to be able to write a function that takes a callback that may or may not be async. To some degree this should be possible since the desugaring of an async function is an ordinary function that returns a Task/Promise/Future. However, I know of no language that is both designed for the efficient transformation-into-state-machine approach and makes it possible to make an await dependent on a type parameter.
await
be elided?. However, your question is about the other part of async/await so it's not a duplicate.