locked
Doing Nothing in Async Methods RRS feed

  • Question

  • Hi,

    What is the recommended way to implement a no-op overridden method that returns Task?

    For example, I've defined an abstract class that has several abstract methods.  The public contract on these methods is that, when implemented, each may return without executing, execute synchronously or execute asynchronously.  I felt that Task was therefore an appropriate return type.  So an implementation might look like this:

    public override Task MaybeDoSomethingMaybeNotMaybeAsync()
    {
      // do nothing - how?
    }

    The most intuitive way to do nothing, IMO, is to simply add the async keyword and then actually do nothing; however, the compiler generates a warning because the await keyword isn't used.  (I'm using VS 11 Beta.)

    So then I decided to look for cached tasks via properties on Task and Task.Factory, but I didn't notice any.  I assumed that something like Task.Completed would exist, but apparently it doesn't.  Eventually I discovered that the following works, though of course it's quite weird:

    return Task.FromResult(0);

    It seems that the recommended solution on the net is the following:

    var tcs = new TaskCompletionSource<int>();
    tcs.SetResult(0);
    return tcs.Task;

    But I find it hard to believe that this is the "standard".  And of course the second issue is that the return type is Task, not Task<TResult>, which makes it that much stranger.

    I can't imagine that people new to async/await are going to find my APIs simple to use if they must use the above code in most of their overridden methods, or some weird and possibly incorrect variants.

    Sorry if this has been discussed already, but a few quick searches found no related topics.

    Thanks,
    Dave


    http://davesexton.com/blog

    Thursday, April 19, 2012 4:21 AM

Answers

  • Hi Dave-

    One option is to just add the async keyword and ignore the compiler's warning.  The warning exists because it's rare that you want to use the async keyword and not have an await... typically it means the developer isn't quite understanding what the async keyword does for them.  But in your case, it's intentional, so you can just suppress the warning, e.g. with a "#pragma warning disable".

    Regarding Completed, it's true that this property doesn't exist today, but that shouldn't stop you from supplying your own that you can use over and over again, e.g.

    private static readonly Task s_completed = Task.Delay(0); // or Task.FromResult(true) or anything else that'll produce an already completed task
    ...
    public override Task MaybeDoSomethingMaybeNotMaybeAsync() { return s_completed; }

    Regarding the TaskCompletionSource solution, the reason that's so common on the net today is because Task.FromResult doesn't exist in .NET 4, so the TCS approach was the next best thing using what was available.  Now that FromResult exists, there's no reason to choose this TCS approach for creating an already successfully completed task.

    Thursday, April 19, 2012 5:23 PM
    Moderator

All replies

  • Can you just return this?

    Task<ofType> task = new Task<ofType>();

    Which is in state of NOTSTARTED?

    JP Cowboy Coders Unite!

    Thursday, April 19, 2012 4:36 AM
  • Why would async trump the ability for a task to run async itself?

    JP Cowboy Coders Unite!

    Thursday, April 19, 2012 4:37 AM
  • Hi,

    Thanks for your response.

    > Can you just return this?  [snip]

    I don't think so, but it's not much better anyway than the other weird solutions.

    Keep in mind that I need a completed, non-generic Task, not an unstarted, generic Task<T>.

    It's true that Task<T> derives from Task, which is why Task.FromResult(0) works, but it's certainly unintuitive for the purpose of returning a completed Task.

    Thanks,
    Dave


    http://davesexton.com/blog

    Thursday, April 19, 2012 5:03 AM
  • Hi,

    > Why would async trump the ability for a task to run async itself?

    Sorry, I don't understand the question.

    - Dave


    http://davesexton.com/blog

    Thursday, April 19, 2012 5:06 AM
  • Hi Dave-

    One option is to just add the async keyword and ignore the compiler's warning.  The warning exists because it's rare that you want to use the async keyword and not have an await... typically it means the developer isn't quite understanding what the async keyword does for them.  But in your case, it's intentional, so you can just suppress the warning, e.g. with a "#pragma warning disable".

    Regarding Completed, it's true that this property doesn't exist today, but that shouldn't stop you from supplying your own that you can use over and over again, e.g.

    private static readonly Task s_completed = Task.Delay(0); // or Task.FromResult(true) or anything else that'll produce an already completed task
    ...
    public override Task MaybeDoSomethingMaybeNotMaybeAsync() { return s_completed; }

    Regarding the TaskCompletionSource solution, the reason that's so common on the net today is because Task.FromResult doesn't exist in .NET 4, so the TCS approach was the next best thing using what was available.  Now that FromResult exists, there's no reason to choose this TCS approach for creating an already successfully completed task.

    Thursday, April 19, 2012 5:23 PM
    Moderator
  • Hi Dave;

      I think what I was asking was this:  We know that the async awiat construct is for Asynchronous stuff.  Be we can also just use a TASK to perform Asyncronous stuff without using Async CTP.  The question then is would it be possible to get what you need without Async CTP use for that particular case.


    JP Cowboy Coders Unite!

    Thursday, April 19, 2012 6:04 PM
  • Hi Stephen,

    Thanks for your reply.

    Just to be clear, I'm writing an API with these methods, not consuming them myself.  My concern is that the consumers of my API are going to be asking the same question as me and currently there's no standard or obvious way of accomplishing my goal.  This means that every dev is going to roll their own solution to this seemingly simple problem.

    For example, I understand that I can just ignore the warning or that I can create my own Task.Completed property, but will others?  And does it make sense for every dev to create their own similar properties like Task.Completed?

    Perhaps it would be best for the compiler to simply not generate a warning for an empty async method.  The semantics are clear.  In what way could a dev be misunderstanding the async keyword if they're leaving the method empty?  Clearly they are attempting to implement a Task that does nothing synchronously and has completed semantics.  Or am I wrong?  Do you see any potential problems if the warning were to be removed?

    Thanks,
    Dave


    http://davesexton.com/blog

    Thursday, April 19, 2012 8:05 PM
  • Hi,

    > [snip] The question then is would it be possible to get what you need without Async CTP use for that particular case.

    I'm not forcing users to use the async keyword.  I'm just offering abstract methods that return Task.  Implementers can return a Task however they can.

    My point about using the async keyword was simply that an empty method was the most intuitive solution for me, but the primary point of my post was actually to ask this question that I started with: What is the recommended way to implement a no-op overridden method that returns Task?

    I.e., What is the standard way to synchronously return a completed Task that does nothing?

    Apparently, the answer is that there is no standard solution.

    I'm definitely not happy with just ignoring the warning (I like having no warnings) or disabling it with a pragma directive.  I'm also a bit concerned that every dev is probably going to roll their own weird solution for this problem when it seems that a simple empty async method should be good enough.

    - Dave


    http://davesexton.com/blog

    • Edited by Dave Sexton Saturday, April 21, 2012 1:05 AM
    Thursday, April 19, 2012 8:15 PM
  • Hi,

    > It does: Task.IsCompleted Property.

    No, that's a read-only instance property.  I was looking for a static field that contained a cached instance of Task with that property already set to true.

    Also, your example is off because I'm using Task not Task<TResult>Task is different because it represents void.

    Thanks anyway though :)

    - Dave


    http://davesexton.com/blog

    Thursday, April 19, 2012 11:18 PM
  • This was the reasoning behind my TaskConstants class in AsyncEx.

    It provides static readonly instances via static properties: BooleanTrue, BooleanFalse, Int32Zero, Int32NegativeOne, and Default. Any of those can be used for an untyped task.

    I hope that some cached completed tasks will be available in .NET 4.5 - at least "Default".

           -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
      and How to Implement IDisposable and Finalizers: 3 Easy Rules
    Microsoft Certified Professional Developer

    How to get to Heaven according to the Bible

    Monday, April 23, 2012 12:25 PM
  • Hi Steve, 

    Thanks, it's good to know that I'm not the only one who sees a need for this.  Though for semantics sake in the case of the non-generic Task, perhaps a simple Completed property would be better.  Or I'd even accept a property called Void to match your pattern of naming the properties based on the return type of the cached object.

    For example, my preference is:

    public override Task MaybeDoSomethingMaybeNotMaybeAsync()
    {
      return Task.Completed;
    }

    But I'd accept something like this:

    public override Task MaybeDoSomethingMaybeNotMaybeAsync()
    {
      return TaskConstants.Void;
    }

    - Dave


    http://davesexton.com/blog

    Monday, April 23, 2012 1:51 PM
  • Actually, my real preference is an empty async method, as stated previously.  But I think that the aforementioned property-based solutions are the next best thing if there's no chance of convincing the C# team to remove the warning for empty async void- and non-generic Task-returning methods.

    - Dave


    http://davesexton.com/blog

    Monday, April 23, 2012 1:54 PM