How about not having a keyword?
I'd like the compiler to realise that, most of the time, when I call an asynchronous method, I want the result of it.
Document doc = DownloadDocumentAsync();
That's it. The reason people are having a hard time thinking up a keyword for this thing is because it's like having a keyword for "do the thing you'd do if things were perfectly normal". That should be the default, not require a keyword.
Update
I originally suggested the compiler should get clever with type inference to figure out what to do. Thinking further about this, I'd keep the existing implementation in the CTP as it is, but make a couple of trivial additions to it, so as to reduce the cases where you'd need to use the await
keyword explicitly.
We invent an attribute: [AutoAwait]
. This can only be applied to methods. One way to get this applied to your method is to mark it async
. But you could also do it by hand, e.g.:
[AutoAwait]
public Task<Document> DownloadDocumentAsync()
Then inside any async
method, the compiler will assume you want to await on a call to DownloadDocumentAsync
, so you don't need to specify it. Any call to that method will automatically await it.
Document doc = DownloadDocumentAsync();
Now, if you want to "get clever" and obtain the Task<Document>
, you use an operator start
, which can only appear before a method call:
Task<Document> task = start DownloadDocumentAsync();
Neat, I think. Now a plain method call means what it usually means: wait for the method to complete. And start
indicates something different: don't wait.
For code that appears outside of an async
method, the only way you're allowed to call an [AutoAwait]
method is by prefixing it with start
. This forces you to write code that has the same meaning regardless of whether it appears in an async
method or not.
Then I start to get greedy! :)
Firstly, I want async
to apply to interface methods:
interface IThing
{
async int GetCount();
}
It basically means that the implementing method must return Task<int>
or something compatible with await
, and callers to the method will get [AutoAwait]
behaviour.
Also when I implement the above method, I want to be able to write:
async int GetCount()
So I don't have to mention Task<int>
as the return type.
Also, I want async
to apply to delegate types (which, after all, are like interfaces with one method). So:
public async delegate TResult AsyncFunc<TResult>();
An async
delegate has - you guessed it - [AutoAwait]
behaviour. From an async
method you can call it and it will automatically be await
ed (unless you choose to just start
it). And so if you say:
AsyncFunc<Document> getDoc = DownloadDocumentAsync;
That just works. It's not a method call. No task has been started yet - an async delegate
is not a task. It's a factory for making tasks. You can say:
Document doc = getDoc();
And that will start a task and wait for it to finish and give you the result. Or you can say:
Task<Document> t = start getDoc();
So one place in this where the "plumbing" leaks out is that if you want to make a delegate to an async
method, you have to know to use an async delegate
type. So instead of Func
you must say AsyncFunc
, and so on. Though one day that kind of thing might be fixed by improved type inference.
Another question is what should happen if you say start on an ordinary (non-async) method. Obviously a compile error would be the safe option. But there are other possibilities.