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 awaited (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.