1

I've got code very similar to this (I've simplified the code a bit to demonstrate the essence of the behavior I'm trying to figure out).

public async System.Threading.Tasks.Task<bool> IsNumberOdd(int numToTest)
{
    if (numToTest % 2 == 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}

If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>. I'm assuming there's some syntactic sugar involved here. Looking at the IL (I'm not super familiar with IL) it seems as if the async keyword is causing the task to be run and then the return value is the result of the task. Am I understanding this correctly?

By the way, if this is a dupe or if there's some blog posting that discusses this, feel free to point me to it and close this up. I'm not trying to pad my rep; I'm trying to understand what's going on with this code.

EDIT:


For all those who were asking "why is this method async?"--because I was trying to build a small and simple code example to demonstrate the question. I should have also added an example of the calling code but I was trying to keep the code as small and simple as I could.

Onorio Catenacci
  • 14,928
  • 14
  • 81
  • 132

3 Answers3

5

I'm assuming there's some syntactic sugar involved here

Not exactly "syntactic sugar". The compiler is generating a state-machine as the method was marked as async. That is why you can return a Task<bool> without explicitly creating a Task for the return value.

If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>.

The async modifier is what triggers the compiler to create the state machine. If you remove it, you'll need to create the Task yourself. If for any reason you want to create a Task<T> but you're actually running synchronously, Task.FromResult is your friend.

I see no reason why this method is marked async.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 1
    I agree that this method doesn't need to be async. I'm trying to simplify code I'm working with. – Onorio Catenacci May 26 '15 at 12:46
  • @OnorioCatenacci Did you receive an answer to your question? I wasn't quite sure what you were asking. – Yuval Itzchakov May 26 '15 at 12:47
  • Re. paragraph #2: an `async` function without any `await` will compile, but with a warning. The `async` automatically wraps the resuilt into a `Task`. – Richard May 26 '15 at 12:48
  • @Richard I know it will compile. Where did I state it wouldn't? – Yuval Itzchakov May 26 '15 at 12:49
  • In an earlier edit... "How can you cast a "future received" value to a bool, if that bool hasn't returned yet?". – Richard May 26 '15 at 12:51
  • Thanks @YuvalItzchakov, you did answer my question. Was trying to mark your answer as accepted but I can't yet. – Onorio Catenacci May 26 '15 at 12:52
  • @Richard That paragraph was because i thought he was trying to cast the return value of the method. But as I understood that wasn't the case, I deleted that section as it is irrelevant. But still, that has nothing to do with what you said, I wasn't talking about compilation. – Yuval Itzchakov May 26 '15 at 12:52
2

it seems as if the async keyword is causing the task to be run and then the return value is the result of the task

Correct.

There is nothing in this method that would benefit from it being async. However:

If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>

Would be happening in the caller. Without seeing that code one can only comment generally that you can either:

  • Change the caller to not assume it is getting a waitable return.
  • Change the function to return bool, but on the caller use Task.FromResult(IsNumberOdd(value)).
Richard
  • 106,783
  • 21
  • 203
  • 265
  • 1
    Simplified demonstration code to isolate the behavior I was wondering about. Yes, it's contrived and not something I'd write for a production system. – Onorio Catenacci May 26 '15 at 12:48
  • @OnorioCatenacci Without the caller of this it is impossible to be specific: being async is part of the contract between caller and callee: they work together. – Richard May 26 '15 at 12:49
0

It's not about the async. Its about the Task.

your returning a bool and the return value of your function is Task

     public Task<bool> DoSomething()
     { 
         return false;
     }

will also not compile. if your not doing any thing asynchronous you shouldn't return a Task.

If you need to run something asynchronously , here are a few options which i hope will make the usage of async/await clearer.

public class Sample
{
    public async void RunSample() 
    {
        // return a task. later obtain a result if some fashion 
        Task<bool> task = DoSomethingAsync();
        bool res1 = task.Result;

        // await a task which is created for you by re-wrapping the result.
        bool res2 = await AwaitSomethingAsync();

        // await a task which is created for you by rewrapping the result due to await.
        bool res3 = await DoSomethingAsync2();

        // await a task.
        bool res4 = await DoSomethingAsync();     
    }


    public async Task<bool> DoSomethingAsync2()
    {
        return false;
    }

    public Task<bool> DoSomethingAsync()
    {
        return Task<bool>.Run(() => { return false; });
    }

    public async Task<bool> AwaitSomethingAsync()
    {
        bool res = await Task<bool>.Run(() => { return false; });
        return res; // re-wraps it in a Task
    }

}
eran otzap
  • 12,293
  • 20
  • 84
  • 139
  • 1
    That's incorrect. The code snippet you provided won't compile. `async` is what triggers the compiler to generate the state-machine. – Yuval Itzchakov May 26 '15 at 12:44
  • The OP is saying it does compile when `async` is added and wants to know why. The OP also states that this is a simplified piece of code to demonstrate the issue, so that is likely why there isn't anything inherently asynchronous about it. – juharr May 26 '15 at 12:45
  • If you add `async` to that code it will compiler: but with a warning that without an `await` it will run synchronously. – Richard May 26 '15 at 12:46
  • Using `Task.Run` for a synchronous operations just to return a `Task` is a horrible, error prone solution. – Yuval Itzchakov May 26 '15 at 12:54
  • @YuvalItzchakov the first sample won't compile and iv'e stated that ! – eran otzap May 26 '15 at 12:55
  • @eranotzap I'm talking about your second example. – Yuval Itzchakov May 26 '15 at 12:57
  • @YuvalItzchakov sorry i wasn't finished i didn't realize i submitted a partial answer. – eran otzap May 26 '15 at 12:59
  • It would compile its just does just not usefull – eran otzap May 26 '15 at 13:00
  • @YuvalItzchakov have a look please. sorry about before i was writing something and submitted it by mistake. and i didn't do Task.FromResult for his benefit not because i an aware of it.. By the way what do you think you'll find under FromResult my guess is Task.Run( ... ) – eran otzap May 26 '15 at 13:06
  • You're still using `Task.Run` to invoke a synchronous operation and make it look like it's async. Thats an [anti-pattern](http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx). – Yuval Itzchakov May 26 '15 at 13:07
  • @YuvalItzchakov no i'm not. you are mistaken . i'm just doing a very very simple example to explain the usage If i write return _myService.SomeLoooonnnngggOperation() , would it suit you better? Task.Run( ) // opens a new thread. i don't care it's going to make coffie or it returns false. you missed the all point – eran otzap May 26 '15 at 13:09
  • I'm sorry, I don't understand what you mean then. – Yuval Itzchakov May 26 '15 at 13:38
  • I really don't get what's wrong with my answer , i just thought in the beginning it didn't compile for him . i demonstrated 2 places he as to have the async keyword in order for it to even compile. the operations i run are asynchronous. – eran otzap May 26 '15 at 14:13
  • 1
    @eranotzap Not sure why your answer got downvoted. It wasn't a question of the example compiling or not but I can see that possibly my question wasn't quite as clear as it might have been. Thanks for your help regardless. – Onorio Catenacci May 26 '15 at 14:57