I am trying get my hands dirty with async CTP and I noticed that the compiler complains about the async return type. What is the problem with other types?
A simple d
On the await [consumption] side, we are flexible: we can await any type so long as it
has the right methods.
On the async method [production] side, we are inflexible: we are hard-coded to
return only the Task type (or void).
Why the inconsistency?
Iterators already have this behavior...
An iterator method (one which has a “yield” inside) is hard-coded to return either IEnumerable or IEnumerator. However, you can “foreach” over any type which has GetEnumerator/MoveNext/Current members. So Async is just following suite.
A task is like a future, so it’s good to hard-code it...
A Task is barely more than a future. A future is a basic fundamental part of a language/platform. There’s no reason for a language two have multiple copies of such a fundamental notion. One is enough. It’s so foundational that you might even add keywords to the language to deal with futures. Anyway, if someone has a future-like thing, or a richer notion of task, then they can build it out of Task or Func. (Our Tasks are already running. If you want to build something that’s “cold”, like F# asyncs or like IObservable, one which doesn’t start until you tell it – then you should build it out of a Func rather than out of a Task).
Further subtleties
Define this function:
void f(Func> f)
And invoke it:
f( () => 1 + await t )
We’d like to be able to infer that T=int in this case. Such inference isn’t possible unless
the compiler has hard-coded knowledge that the lambda it passes to “f” has type
Task.
Source: Technical intro to the Async CTP