Home > .NET, C# 5 > Something wrong with async, await and the Task(Task)

Something wrong with async, await and the Task(Task)

Hi all

 

This is my first blog :), so please excuse me (or point me) for any fault.

 

Whenever something new comes I usually analyze it in my own way figuring out its good and bad and whys. This is the first time I am thinking aloud via blogs.

 

Something wrong with async, await and the Task(Task<T>)

 

There is something wrong with the method modifier (async) and operator (await), something is not in place

Somehow I feel that async, await and Task triplet does not fit in the language rules and expectations

 

Lest analyze this in three parts –

1.      Analyze method invocation statement.

2.      Analyze method declaration statement

3.       Analyze method return statement.

 

1. Analyze method invocation statement –

 

Consider these two statements

Task<int> u =       ReturnIntAsync();

int       t = await ReturnIntAsync();

 

Expected – LHS and RHS must be of same data type.

 

first statement, no problem there, it clearly states that ReturnIntAsync() method must have Task<int> as return type and this is the case. Second statement, no problem, it looks like await must be pulling out the Result, which is int, from Task and returning it (in addition to its actual functionality, that is, returning back to the caller after asynchronously invoking the ReturnIntAsync() method).

 

So Actual – LHS and RHS are of same data type.

 

2. Analyze method declaration statement –

 

The method declaration –

async public static Task<int> ReturnIntAsync()

 

Expected – Must match with the caller in terms of return type and function prototype.

 

There are three method modifiers in this statement, static only one copy of this method will be created, public it’s a no restriction access modifier, async marks the method for asynchronous calling.

None of the above method modifier changed return type or function prototype.

 

Actual – Perfectly matching.

 

3. Analyze method return statement –

 

Expected – it must match with the of return statement of function definition

 

Now take a look at the method body –

async public static Task<int> ReturnIntAsync()

{

    return 0;

}

 

No need to discuss anything its clearly not matching. By no means the value zero(0) can be thought of implicitly converted to Task<int>.

 

Actual – both are different.

 

So, async modifier is responsible of this mis-behavior.

 

Why

So, before asking the question lets analyze the situation and try some alternatives.

 

First alternative that comes to my mind is to simply change the function definition to return int instead of Task<int> and let the compiler automatically takes care of int and Task<int>. But that’s not possible because at the callers end Task<int> is not getting converted to int by using the await keyword, it’s Task<int>.Result which is an int (see point 1 – analysis of caller). Also, it’s the method which is creating a task and returning it and not the caller who is creating the task out of int.

 

Second alternative, we can have a special kind of return statement like async return or task return, which will return the Task<int> instead of int. See below examples –

async public static Task<int> ReturnIntAsync()

{

    return 0; //instead

    async return 0; //use this

    task return 0; //or this

    return task 0; //or this

    return async 0; //or this

}

Now this will make sense, as we are applying some operator to the returning value which can be assumed attaching the return value to the task. At first I thought that just for the sake of readability and making the statement complete should we introduce a new keyword. But then I thought why not if you recall as soon as you apply the async modifier the method is no more returning what it was returning previously instead it is attaching the value of return to the task.

 

So to conclude I strongly think that something must be done with the return statement. I am sure it must be a big pain to change something in the language but that’s my view with the potential problem and the solution :).

Advertisements
Categories: .NET, C# 5
  1. November 8, 2010 at 10:44 pm

    In my opinion, the return statement is the one correct part! 🙂 Logically, the method returns that value, and it makes perfect sense to use existing C# syntax to represent an identical logical concept (even though the technical implementation is different).

    So it is the other parts that need to change to be consistent. The return type:

    async public static int ReturnIntAsync()

    Logically, the method returns an int. So that should be the declaration. The compiler takes care of making it return Task “behind the scenes”.

    Finally, when calling it, instead of:

    Task u = ReturnIntAsync();
    int t = await ReturnIntAsync();

    It should be like this:

    Task u = start ReturnIntAsync();
    int t = ReturnIntAsync();

    Again, this gives exact consistency with the normal C# way of writing a method call that will wait for the called method to complete and obtain the result.

    “start” would be a new keyword. Technically (behind the scenes) it switches off the new capabilities of the C# 5 compiler for that method call.

    To implement the “default await” idea, suitable methods would need an attribute, something like [AutoAwait]. This attribute would be applied to any method declared with the async modifier.

    If these changes are made, the technical details of the difference between async and normal methods are abstracted away. We can write and understand the flow of our code in the same way regardless of whether methods have the async prefix or not.

    • November 10, 2010 at 3:55 am

      Agreed, what you suggested absolutely make sense, however, only concern is –
      Task u = start ReturnIntAsync();
      this implies that “start” is doing something with the int to return a Task, but that’s not the case instead it’s the method who is generating the task. So somehow that method should indicate its return type as Task.
      Similar to yield return case, we have a return type of IEnumerable and we are returning an int, one at a time. We could have a keyword(say enumer) then the statement could be – foreach( int i in enumer GetYieldResult()) and simply return int from GetYieldResult().

  1. December 2, 2010 at 10:20 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: