July 9th, 2024

Creating an already-completed asynchonous activity in C++/WinRT, part 1

When working with asynchronous code, you may need to create an asynchronous activity that has already completed, because you already know the answer. For example, you may be implementing a method whose signature is

IAsyncOperation<int> ComputeAsync();

but you already have the result and don’t need to compute it. How can you return an IAsyncOperation<int> that represents the already-computed result?

C# has Task.FromResult() and Task.CompletedTask. JavaScript has Promise.resolve(). The Parallel Patterns Library (PPL) has task_from_result(). What about C++/WinRT?

The simplest way is to just co_return the result into a coroutine.

winrt::Windows::Foundation::IAsyncOperation<int>
    ComputeAsync()
{
    co_return 42;
}

Similarly, C# has Task.FromException(), JavaScript has Promise.reject(), and PPL has task_from_exception(). The simple C++/WinRT version is to throw the exception from the coroutine.

But wait, this doesn’t do what you think:

winrt::Windows::Foundation::IAsyncOperation<int>
    ComputeAsync()
{
    throw winrt::hresult_access_denied();
}

There is no co_await or co_return statement in the function body, so this is not a coroutine: Instead of returning a failed coroutine, this function fails to return a coroutine! When you call it, it throws an exception.

We’ll look at ways of making this a coroutine next time.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Jacob Manaker

    Perhaps the following?

    
    winrt::Windows::Foundation::IAsyncOperation<int> ComputeAsync(void) noexcept
    {
        co_await std::suspend_never{};
        throw winrt::hresult_access_denied();
    }
    
    • LB

      I’m not sure how IAsyncOperation’s promise type handles the situation where dynamic allocation of the coroutine frame fails, that usually results in throwing std::bad_alloc, so you can’t mark the function as noexcept in that case. If it has some non-throwing way of handling that case though then I suppose the noexcept is fine. It’s a shame there’s no way for a promise type to detect whether the function signature contains noexcept or not.