{"id":108640,"date":"2023-08-23T07:00:00","date_gmt":"2023-08-23T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108640"},"modified":"2023-08-23T07:07:09","modified_gmt":"2023-08-23T14:07:09","slug":"20230823-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230823-00\/?p=108640\/","title":{"rendered":"On writing loops in PPL and continuation-passing style, part 2"},"content":{"rendered":"<p>Last time, <a title=\"On writing loops in PPL and continuation-passing style, part 1\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230822-00\/?p=108634\"> we came up with task-based <code>while<\/code> loop<\/a> that involved creating a custom callable that passed copies of itself to the next iteration.<\/p>\n<p>This time, we&#8217;ll implement the function in terms of a more traditional recursion.<\/p>\n<pre>template&lt;typename Callable&gt;\r\ntask&lt;void&gt; do_while_task(\r\n    std::shared_ptr&lt;Callable&gt; const&amp; f)\r\n{\r\n    return (*f)().then([f](bool loop) {\r\n        return loop ? do_while_task(f) :\r\n                      task_from_result();\r\n    });\r\n}\r\n\r\ntemplate&lt;typename Callable, typename =\r\n    std::enable_if_t&lt;std::is_invocable_v&lt;Callable&gt;&gt;&gt;\r\ntask&lt;void&gt; do_while_task(Callable&amp;&amp; callable)\r\n{\r\n    using Decayed = std::decay_t&lt;Callable&gt;;\r\n    return do_while_task(\r\n        std::make_shared&lt;Decayed&gt;(\r\n            std::forward&lt;Callable&gt;(callable)));\r\n}\r\n<\/pre>\n<p>The real work happens in the first overload, which takes a ready-made <code>shared_ptr<\/code>. The second overload is a convenience method that lets you pass a callable, and it will wrap it in a <code>shared_ptr<\/code> for you.<\/p>\n<p>However, if you think about it, in PPL-style programming, the lambda callable itself usually holds a pointer to shared state, so that the various task fragments can share information with each other. Let&#8217;s look again at my original example.<\/p>\n<pre>do_while_task([i = 0, widgets]() mutable\r\n{\r\n    if (i &gt;= 3) return task_from_result(false);\r\n    return create_widget().then([index = i++, widgets](auto widget)\r\n    {\r\n        widgets[index] = widget;\r\n        return true;\r\n    });\r\n}).then([] {\r\n    printf(\"Done!\\n\");\r\n});\r\n<\/pre>\n<p>I cheated here and incremented the <code>i<\/code> variable inside the first lambda, but capturing the unincremented value as <code>index<\/code> for the second lambda. More realistically, the two lambdas need to share state.<\/p>\n<pre><span style=\"border: solid 1px currentcolor; border-bottom: none;\">struct lambda_state                                  <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">{                                                    <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    lambda_state(Widgets* w) : widgets(w) {}         <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    Widgets* widgets;                                <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">    int i = 0;                                       <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">};                                                   <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">\u00a0                                                    <\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">auto state = std::make_shared&lt;lambda_state&gt;(widgets);<\/span>\r\n\r\ndo_while_task([<span style=\"border: solid 1px currentcolor;\">state<\/span>]()\r\n{\r\n    if (<span style=\"border: solid 1px currentcolor;\">state-&gt;<\/span>i &gt;= 3) return task_from_result(false);\r\n    return create_widget().then([<span style=\"border: solid 1px currentcolor;\">state<\/span>](auto widget)\r\n    {\r\n        <span style=\"border: solid 1px currentcolor;\">state-&gt;<\/span>widgets[<span style=\"border: solid 1px currentcolor;\">state-&gt;<\/span>i] = widget;\r\n        <span style=\"border: solid 1px currentcolor;\">state-&gt;<\/span>i++;\r\n        return true;\r\n    }\r\n}).then([] {\r\n    printf(\"Done!\\n\");\r\n});\r\n<\/pre>\n<p>This means that our <code>do_while_task<\/code> creates a <code>shared_ptr<\/code> that itself holds another <code>shared_ptr<\/code>, which seems kind of silly.<\/p>\n<p>We&#8217;ll address this next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recursion comes back.<\/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-108640","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Recursion comes back.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108640","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=108640"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108640\/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=108640"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108640"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108640"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}