{"id":103197,"date":"2019-12-10T07:00:00","date_gmt":"2019-12-10T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103197"},"modified":"2019-12-09T18:38:11","modified_gmt":"2019-12-10T02:38:11","slug":"20191210-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191210-00\/?p=103197","title":{"rendered":"C++ coroutines: Constructible awaitable or function returning awaitable?"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191209-00\/?p=103195\"> Last time<\/a>, we learned how to create simple awaitable objects by creating a structure that implements the <code>await_<\/code><code>suspend<\/code> method (and relies on <code>suspend_<\/code><code>always<\/code> to do the coroutine paperwork for us). We can then construct the awaitable object and then <code>co_await<\/code> on it.<\/p>\n<p>As a reminder, here&#8217;s our <code>resume_<\/code><code>new_<\/code><code>thread<\/code> structure:<\/p>\n<pre>struct resume_new_thread : std::experimental::suspend_always\r\n{\r\n  void await_suspend(\r\n      std::experimental::coroutine_handle&lt;&gt; handle)\r\n  {\r\n    std::thread([handle]{ handle(); }).detach();\r\n  }\r\n};\r\n<\/pre>\n<p>Another option is to write a function that returns a simple awaitable object, and <code>co_await<\/code> on the return value.<\/p>\n<pre><span style=\"color: blue;\">auto resume_new_thread()\r\n{<\/span>\r\n  struct awaiter : std::experimental::suspend_always\r\n  {\r\n    void await_suspend(\r\n        std::experimental::coroutine_handle&lt;&gt; handle)\r\n    {\r\n      std::thread([handle]{ handle(); }).detach();\r\n    }\r\n  };\r\n  <span style=\"color: blue;\">return awaiter{};\r\n}<\/span>\r\n<\/pre>\n<p>What&#8217;s the difference? Which is better?<\/p>\n<p>Both awaitable object patterns let you put instance members on the awaitable object:<\/p>\n<pre>auto o = blah();\r\no.configure_something(true);\r\nco_await o;\r\n\r\n\/\/ fluent interface pattern\r\nco_await blah().configure_something(true);\r\n<\/pre>\n<p>In order to have static members, the type must be publicly visible.<\/p>\n<pre>\/\/ blah can be a struct but not a function\r\nco_await blah::fluffy();\r\n<\/pre>\n<p>Both of the patterns permit the <code>blah<\/code> to be parameterized:<\/p>\n<pre>co_await blah(1, false);\r\n<\/pre>\n<p>but only the function pattern permits a different awaitable object to be returned based on the parameter types. That&#8217;s because the function pattern lets you create a different overloaded function for each set of parameters.<\/p>\n<pre>co_await blah(1);       \/\/ awaits whatever blah(int) returns\r\nco_await blah(false);   \/\/ awaits whatever blah(bool) returns\r\n<\/pre>\n<p>The function version also supports marking the return value as <code>[[nodiscard]]<\/code>, which recommends that the compiler issue a warning if the return value is not consumed. This avoids a common mistake of writing<\/p>\n<pre>blah();\r\n<\/pre>\n<p>instead of<\/p>\n<pre>co_await blah();\r\n<\/pre>\n<p>Let&#8217;s make a comparison table.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Property<\/th>\n<th>struct<\/th>\n<th>function<\/th>\n<\/tr>\n<tr>\n<td>Instance members<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Static members<\/td>\n<td>Yes<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>Allows parameters<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Different awaitable type<br \/>\ndepending on parameter types<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Different awaitable type<br \/>\ndepending on parameter values<\/td>\n<td>No<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>Warn if not <code>co_await<\/code>ed<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Note that neither gives you the ability to change the awaitable type based on the parameter <i>values<\/i>.)<\/p>\n<p>Here&#8217;s a sketch of how each pattern would implement what it can:<\/p>\n<pre>struct blah : std::experimental::suspend_always\r\n{\r\n  void await_suspend(\r\n      std::experimental::coroutine_handle&lt;&gt; handle);\r\n\r\n  \/\/ instance member, fluent interface pattern\r\n  blah&amp; configure_something(bool value);\r\n\r\n  \/\/ static member\r\n  static blah fluffy();\r\n\r\n  \/\/ parameterized\r\n  blah();\r\n  blah(int value);\r\n  blah(bool value);\r\n};\r\n\r\n\/\/ function pattern\r\n[[nodiscard]] auto blah()\r\n{\r\n  struct awaiter : std::experimental::suspend_always\r\n  {\r\n    void await_suspend(\r\n        std::experimental::coroutine_handle&lt;&gt; handle) { ... }\r\n\r\n    \/\/ instance member, fluent interface pattern\r\n    awaiter&amp; configure_something(bool value) { ... }\r\n  };\r\n  return awaiter{};\r\n}\r\n\r\n[[nodiscard]] auto blah(int value)\r\n{\r\n  struct awaiter : std::experimental::suspend_always\r\n  {\r\n    void await_suspend(\r\n        std::experimental::coroutine_handle&lt;&gt; handle) { ... }\r\n\r\n    \/\/ instance member, used only for blah(int)\r\n    awaiter&amp; configure_int(bool value) { ... }\r\n  };\r\n  return awaiter{};\r\n}\r\n\r\n[[nodiscard]] auto blah(bool value)\r\n{\r\n  struct awaiter : std::experimental::suspend_always\r\n  {\r\n    void await_suspend(\r\n        std::experimental::coroutine_handle&lt;&gt; handle) { ... }\r\n\r\n    \/\/ instance member, used only for blah(bool)\r\n    awaiter&amp; configure_bool(bool value) { ... }\r\n  };\r\n  return awaiter{};\r\n}\r\n<\/pre>\n<p>The upside of the function pattern is that you can have completely different implementations depending on which overload is called. The downside is that you end up repeating yourself a lot. Though you may be able to reduce some of the extra typing by factoring into a base class in an implementation namespace.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Two common patterns for simple awaitable objects.<\/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-103197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Two common patterns for simple awaitable objects.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103197","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=103197"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103197\/revisions"}],"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=103197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103197"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}