Thoughts on simplifying Async
- Dominant language
- No language data
- Stars
- 328
- Forks
- 71
- PR merge metrics
- No merged PRs in 30d
Description
Since it's initial release I've wanted to go back and take another pass at simplifying the experience of `Async`/`Await`. I had some ideas of how to make the design simpler while we were designing the feature originally but we struggled to come up with a model that was flexible and consistent. I've heard a lot of stories from customers about where they or developers they know have tripped over themselves and these problems keep coming up again and again:
* `Async Sub` is easily misused.
* `ConfigureAwait` is easily forgotten.
* `Await` is on the left.
The last one is more an annoyance while the first two are in my opinion gaping flaws in an otherwise elegant feature. I'm kicking off this thread as a sort of "thinking out loud" space.
I think the model we have today where there are two kinds of synchronous methods:
* Subs, which don't return a value, and
* Functions, which do
But _three_ kinds of asynchronous methods:
* `Task`-returning async methods, which asynchronously don't return a value,
* `Task(Of T)`-returning async methods, which asynchronously do return a value, and
* void-returning async methods, which asynchronously don't return a value and can't be awaited
Is 50% more kinds of methods than we need. And the only real motivation for having them is method overrides and event handlers whose existing signatures are incompatible with returning a value. But VB already has the ability to handle this through delegate relaxation. In fact, we added a special warning to VB so that if you do try to drop the return value of a `Task`-returning async function through delegate relaxation, we report a warning.
Here's what I want:
* `Async Sub M()` to translate to `Async Function M() As Task`, and
* `Async Function M() As T` to translate to `Async Function M() As Task(Of T)`
We can do it compatibly a couple of ways:
* The magic `Option` statement. I think such a simplification would be worth it.
* A more target heuristic: In a future version of VB `Async Sub` declarations could be awaitable but preserve the existing behavior if they aren't awaited (which they can't be today) or hooked up to an event handler. And `Async Function` declarations which return a type _other than_ `Task` or `Task(Of T)` will be interpreted as return `Task(Of T)` where `T` is their stated return type.
The latter approach has a slight problem in the rare case that you want to asynchronously return a task (e.g. `WaitAny`) you'd still need to use the syntax `Task(Of Task)`. There are _some_ ways we can mitigate that. And it also doesn't help a situation where today someone is passing an `Async Sub` lambda to a method that takes a synchronous delegate. We also report a warning if an asynchronous delegate-taking overload exists but this would still represent a change in behavior, which I find extremely distasteful. That makes more more inclined to deprecation through an `Option` statement.
The problem with all of this is coming up with a model that is consistent. Particularly an IDE experience. Gotta go. Will keep adding thoughts later.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.