{"id":112354,"date":"2026-05-26T07:00:00","date_gmt":"2026-05-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112354"},"modified":"2026-05-26T14:05:00","modified_gmt":"2026-05-26T21:05:00","slug":"20260526-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260526-00\/?p=112354","title":{"rendered":"If C# and JavaScript lets me await a Windows Runtime asynchronous operation more than once, why not C++\/WinRT?"},"content":{"rendered":"<p>The Windows Runtime expresses asynchronous execution in the form of types like <code>IAsync\u00adOperation<\/code>. Different languages choose to represent this concept in different ways.<\/p>\n<ul>\n<li>C# wraps it inside a <code>System.<wbr \/>Threading.<wbr \/>Tasks.<wbr \/>Task<\/code>.<\/li>\n<li>JavaScript wraps it inside a <code>Promise<\/code>.<\/li>\n<li>Python wraps it inside an <code>asyncio.<wbr \/>Future<\/code>.<\/li>\n<\/ul>\n<p>All of the above wrappers support multiple continuations, which means that you can call <code>await<\/code> on them multiple times.<\/p>\n<p>But C++\/WinRT doesn&#8217;t provide such a wrapper. C++\/WinRT just exposes the original <code>IAsync\u00adOperation<\/code>. The <code>IAsync\u00adOperation<\/code> doesn&#8217;t allow multiple continuations to be attached, so you cannot <code>co_await<\/code> it multiple times.<\/p>\n<p>Boo.<\/p>\n<p>Why doesn&#8217;t C++\/WinRT get with the program and provide a wrapper that supports multiple continuations?<\/p>\n<p>Well, one reason is that C#&#8217;s <code>System.<wbr \/>Threading.<wbr \/>Tasks.<wbr \/>Task<\/code>, JavaScript&#8217;s <code>Promise<\/code>, and Python&#8217;s <code>asyncio.<wbr \/>Future<\/code> are part of the respective languages&#8217; 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.<\/p>\n<p>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 <a title=\"A map through the three major coroutine series\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210504-01\/?p=105178\"> back when we learned about C++ coroutines<\/a> and implemented a <code>simple_task<\/code> class.<\/p>\n<p>The lack of a standard library <code>task<\/code> type means that there isn&#8217;t a pre-existing wrapper that C++ projections could take advantage of. It&#8217;s every man for himself.<\/p>\n<p>C++\/WinRT provides a minimal coroutine promise for <code>IAsync\u00adOperation<\/code> in deference to the general C++ principle of &#8220;you don&#8217;t pay for what you don&#8217;t use.&#8221; The overwhelming majority of the time, you have no need to await an <code>IAsync\u00adOperation<\/code> more than once, so why make every <code>IAsync\u00adOperation<\/code> pay for it?<\/p>\n<p>Next time, we&#8217;ll look at a case where you would want to await an <code>IAsync\u00adOperation<\/code> more than once, and see what we can do to work around the C++\/WinRT limitation.<\/p>\n<p><b>Bonus chatter<\/b>: There does exist a pre-existing library that supports multiple continuations: The Parallel Patterns Library <code>concurrency::<wbr \/>task<\/code> object. The older C++\/CX projection does not natively wrap the <code>IAsyncOperation^<\/code>, but the Parallel Patterns Library does have special knowledge of the C++\/CX <code>IAsyncOperation^<\/code>, so you can wrap an <code>IAsyncOperation^<\/code> inside a PPL <code>task<\/code> and <code>co_await<\/code> the <code>task<\/code> more than once.<\/p>\n<p>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 <i>so many features<\/i>, most of which you probably aren&#8217;t using. You could say that while C++\/WinRT tries to be minimalist, PPL tries to be maximalist. It&#8217;s easier to start small and grow and it is to start big and try to pare back. (And C++\/WinRT generally delegates the &#8220;grow&#8221; part to the Windows Implementation Library, which adds additional features with headers like <tt>cppwinrt_helpers.h<\/tt> and <tt>cppwinrt_authoring.h<\/tt>.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A difference in philosophy.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-112354","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A difference in philosophy.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112354","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=112354"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112354\/revisions"}],"predecessor-version":[{"id":112355,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112354\/revisions\/112355"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=112354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}