The Windows Runtime expresses asynchronous execution in the form of types like IAsyncÂOperation. Different languages choose to represent this concept in different ways.
- C# wraps it inside a
System..Threading. Tasks. Task - JavaScript wraps it inside a
Promise. - Python wraps it inside an
asyncio..Future
All of the above wrappers support multiple continuations, which means that you can call await on them multiple times.
But C++/WinRT doesn’t provide such a wrapper. C++/WinRT just exposes the original IAsyncÂOperation. The IAsyncÂOperation doesn’t allow multiple continuations to be attached, so you cannot co_await it multiple times.
Boo.
Why doesn’t C++/WinRT get with the program and provide a wrapper that supports multiple continuations?
Well, one reason is that C#’s System., JavaScript’s Promise, and Python’s asyncio. are part of the respective languages’ standard libraries. This makes them an obvious choice for projection since they are a way to represent asynchronous execution that is universally understood by anybody writing code in that language. Furthermore, the fact that they are standard library features lets the projections build on the work of others: The standard library maintainers have already implemented, tested, and optimized these classes.
C++ does not have a standard library for asynchronous execution. Instead, C++ provides raw materials out of which you can write your own library. And we wrote one such library back when we learned about C++ coroutines and implemented a simple_task class.
The lack of a standard library task type means that there isn’t a pre-existing wrapper that C++ projections could take advantage of. It’s every man for himself.
C++/WinRT provides a minimal coroutine promise for IAsyncÂOperation in deference to the general C++ principle of “you don’t pay for what you don’t use.” The overwhelming majority of the time, you have no need to await an IAsyncÂOperation more than once, so why make every IAsyncÂOperation pay for it?
Next time, we’ll look at a case where you would want to await an IAsyncÂOperation more than once, and see what we can do to work around the C++/WinRT limitation.
Bonus chatter: There does exist a pre-existing library that supports multiple continuations: The Parallel Patterns Library concurrency:: object. The older C++/CX projection does not natively wrap the IAsyncOperation^, but the Parallel Patterns Library does have special knowledge of the C++/CX IAsyncOperation^, so you can wrap an IAsyncOperation^ inside a PPL task and co_await the task more than once.
So I guess you could say that somebody already wrote the wrapper for you. Unfortunately, that wrapper is quite bulky because the PPL library has so many features, most of which you probably aren’t using. You could say that while C++/WinRT tries to be minimalist, PPL tries to be maximalist. It’s easier to start small and grow and it is to start big and try to pare back. (And C++/WinRT generally delegates the “grow” part to the Windows Implementation Library, which adds additional features with headers like cppwinrt_helpers.h and cppwinrt_authoring.h.)
0 comments
Be the first to start the discussion.