9

What do I return from D4()?

async static Task D4()
{
    Console.Write("Enter the divisor: ");
    var n = int.Parse(Console.ReadLine());
    Console.WriteLine((24 / n).ToString());

    // NONE OF THESE WORK
    // THE COMPILER COMPLAINS WITH AN ERROR THAT SAYS:
    // Since 'Program.D4()' is an async method that returns 'Task', 
    // a return keyword must not be followed by an object expression.
    // Did you intend to return 'Task<T>'?
    // return new TaskCompletionSource<object>().Task;
    // return Task.FromResult<object>(null);
    // return Task.FromResult<bool>(false);
    // return Task.FromResult(0);
}

I asked something similar earlier and it probably worked in my situation then but I have no recollection of the situation now. Also, this thread seems to suggest the same thing that I am trying. I am not sure why it doesn't work in my case.

UPDATE

For the sake of completeness, here is the whole of the relevant bit of code.

async static Task A4() { await B4(); }
async static Task B4() { await C4(); }
async static Task C4() { await D4(); }
async static Task D4()
{
    Console.Write("Enter the divisor: ");
    var n = int.Parse(Console.ReadLine());
    Console.WriteLine((24 / n).ToString());

    // return new TaskCompletionSource<object>().Task;
    // return Task.FromResult<object>(null);
    // return Task.FromResult<bool>(false);
    // return Task.FromResult(0);
}
Community
  • 1
  • 1
Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
  • 4
    nothing... this should work... – M.kazem Akhgary Jun 05 '16 at 21:18
  • 4
    You don't return anything. Treat it as if it was a `void` method. – BJ Myers Jun 05 '16 at 21:22
  • Before worrying about making it async at all, first decide what this method *does*. Which is what? In an entirely non-async world, does this method return anything? – David Jun 05 '16 at 21:23
  • @David You are right. I would in a real project. I am just trying to throw an exception from `D4()` to see if its context is preserved at the top of the call-stack in the `Main` method. `Main` calls `A` calls `B` calls `C` calls `D` -- each awaiting the other except there are no awaits in the `Main` because that's the entry point. – Water Cooler v2 Jun 05 '16 at 21:25
  • Does your version of .NET support `Task.CompletedTask;` ? – H H Jun 05 '16 at 21:26
  • @HenkHolterman No, that's v4.6. I am targeting v4.5.2. – Water Cooler v2 Jun 05 '16 at 21:26
  • 1
    @WaterCoolerv2: So... If this method wouldn't otherwise return anything in a non-async world, why is it trying to return something in an async world? An `async Task` method just needs to internally await something. – David Jun 05 '16 at 21:26
  • 3
    @David: It doesn't actually *have* to await anything... but you'll get a warning if it doesn't. – Jon Skeet Jun 05 '16 at 21:27
  • I am confused, I know I can return `void` but the documentation recommends that we return `Task` instead so the caller can query for the completion or cancellation or the occurance of exceptions in the task, which is why I have the signature returning a `Task` instead. – Water Cooler v2 Jun 05 '16 at 21:31
  • http://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void – M.kazem Akhgary Jun 05 '16 at 21:32
  • @M.kazemAkhgary What the anwer in that link says is also what I was saying. I wasn't asking the question about when to have the return type be a `Task` as against `void`. I was, in fact, politely saying to the person who suggested that I make the return type `void` that what they were saying went against the grain. It wasn't a sound suggestion. – Water Cooler v2 Jun 06 '16 at 13:27

4 Answers4

40

You can think of async as constructing a Task wrapper for you. If you don't use async, then you can return an actual Task object.

Your first code example is using async but then you try to return a Task. Returning a Task isn't necessary with async:

async static Task D4()
{
  Console.Write("Enter the divisor: ");
  var n = int.Parse(Console.ReadLine());
  Console.WriteLine((24 / n).ToString());

  return; // May be removed, since it is implicit.
}

Your second code example removed the async and then tries to not return anything; in this case, since async isn't creating a Task for you, you need to create one yourself:

static Task D4()
{
  Console.Write("Enter the divisor: ");
  var n = int.Parse(Console.ReadLine());
  Console.WriteLine((24 / n).ToString());

  return Task.FromResult(0);
}

The first example (where async creates the Task for you) is more idiomatic. Note that you should also be using an await in the async method.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
4

Remove the async keyword so it becomes

static Task D4()
{
    return Task.FromResult(0); // or one of the others from your post
}

You don't need to await a Task.FromResult(). Even if you would use a Task that does actual work using Task.Run() as the last part of the method. See Awaiting tasks: Return task or await if no code after await

Community
  • 1
  • 1
Peter Bons
  • 26,826
  • 4
  • 50
  • 74
  • 3
    The latter part is incorrect. Basically, you should treat an `async Task` method as if it were a `void` method; plain `return;` statements are fine, but you can't return a value. – Jon Skeet Jun 05 '16 at 21:23
  • My bad, 2nd option shouldn't return anything indeed – Peter Bons Jun 05 '16 at 21:26
  • 1
    There's no point in awaiting `Task.FromResult` though. As that's always a completed task, it'll reach the end of the method synchronously. – Jon Skeet Jun 05 '16 at 21:27
  • Exactly, technically it compiles and works but I gather the actual implementation will be different so I outlined both possibilities – Peter Bons Jun 05 '16 at 21:28
  • 2
    I don't see why there's an "exactly" there - just remove the body of the second part entirely. You don't need to await anything. – Jon Skeet Jun 05 '16 at 21:30
1

You don't return anything from a function with Task as the return type. Similar to what you would do with void.

You could however use "return;" again as you could do with void.

Edit

You should be able to return nothing if you include "async" in the function deceleration.

Example form dotnetfiddle

Tarek
  • 1,219
  • 13
  • 18
0

Well, I returned default(Task) just to make it shut up. I am not sure what the purists will say about that. It seems to have worked and it is harmless I think?

static Task D4()
{
    Console.Write("Enter the divisor: ");
    var n = int.Parse(Console.ReadLine());
    Console.WriteLine((24 / n).ToString());

    // return new TaskCompletionSource<object>().Task;
    // return Task.FromResult<object>(null);
    // return Task.FromResult<bool>(false);
    // return Task.FromResult(0);

    return default(Task);
}

One criticism of this is that the caller will have no idea about what it has received and what its state is. This is an example and I don't really care but as a general principle, I think what I have illustrated should be avoided.

A slightly more safe but expensive approach might be to say this perhaps?

private static Task cachedNoOpTask = new Task(null);

...

return cachedNoOpTask;
Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
  • 1
    This will return null which is probably not what callers will expect. Your question is about `async` methods while `D4` is not marked `async`. You should be able to use `Task.FromResult` to return a completed task since `Task` extends `Task`. If you make `D4` async then you should not return a value. – Lee Jun 05 '16 at 21:43
  • @Lee Sorry, `D4` *was* marked `async` earlier but I posted the updated code in the interm of trying out various recommendations. I must have removed the `async` keyword during then. I have updated the code in the question. – Water Cooler v2 Jun 05 '16 at 21:45
  • Your updated async version of `D4` compiles, although you should get a warning about making it `async` since it doesn't `await` anything. – Lee Jun 05 '16 at 21:48