{"id":108647,"date":"2023-08-24T07:00:00","date_gmt":"2023-08-24T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108647"},"modified":"2023-08-24T07:01:21","modified_gmt":"2023-08-24T14:01:21","slug":"20230824-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230824-00\/?p=108647","title":{"rendered":"On writing loops in PPL and continuation-passing style, part 3"},"content":{"rendered":"<p>Last time, <a title=\"On writing loops in PPL and continuation-passing style, part 2\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230823-00\/?p=108640\"> we wrote a task-based <code>while<\/code> loop using recursion<\/a>, using a <code>shared_ptr<\/code> to pass state, and we noted a redundancy in that we created a <code>shared_ptr<\/code> to a lambda that in turn held a <code>shared_ptr<\/code>.<\/p>\n<p>We can eliminate the nested shared pointers by requiring that all the state live inside a caller-provided <code>shared_ptr<\/code>, levaing the callable stateless.<\/p>\n<pre>template&lt;typename State&gt;\r\ntask&lt;void&gt; do_while_task(\r\n    std::shared_ptr&lt;State&gt; const&amp; state,\r\n    bool (*f)(std::shared_ptr&lt;State&gt; const&amp;)\r\n{\r\n    return f(state).then([state, f](bool loop) {\r\n        return loop ? do_while_task(state, f) :\r\n                      task_from_result();\r\n    });\r\n}\r\n\r\nstruct lambda_state\r\n{\r\n    lambda_state(Widgets* w) : widgets(w) {}\r\n    Widgets* widgets;\r\n    int i = 0;\r\n};\r\n\r\nauto state = std::make_shared&lt;lambda_state&gt;(widgets);\r\n\r\ndo_while_task(state, [](auto&amp;&amp; state)\r\n{\r\n    if (state-&gt;i &gt;= 3) return task_from_result(false);\r\n    return create_widget().then([state](auto widget)\r\n    {\r\n        state-&gt;widgets[state-&gt;i] = widget;\r\n        state-&gt;i++;\r\n        return true;\r\n    }\r\n}).then([] {\r\n    printf(\"Done!\\n\");\r\n});\r\n<\/pre>\n<p>We can get rid of all the <code>state-&gt;<\/code> prefixes by making the state be invocable.<\/p>\n<pre>template&lt;typename State&gt;\r\ntask&lt;void&gt; do_while_task(\r\n    std::shared_ptr&lt;State&gt; const&amp; state)\r\n{\r\n    return (*state)().then([state](bool loop) {\r\n        return loop ? do_while_task(state) :\r\n                      task_from_result();\r\n    });\r\n}\r\n\r\nstruct lambda_state\r\n    : std::enable_shared_from_this&lt;lambda_state&gt;\r\n{\r\n    lambda_state(Widgets* w) : widgets(w) {}\r\n    Widgets* widgets;\r\n    int i = 0;\r\n\r\n    task&lt;bool&gt; operator()()\r\n    {\r\n        if (i &gt;= 3) return task_from_result(false);\r\n        return create_widget().then(\r\n            [this, lifetime = shared_from_this()](auto widget)\r\n        {\r\n            widgets[i] = widget;\r\n            i++;\r\n            return true;\r\n        });\r\n    }\r\n};\r\n\r\nauto state = std::make_shared&lt;lambda_state&gt;(widgets);\r\n\r\ndo_while_task(state).then([] {\r\n    printf(\"Done!\\n\");\r\n});\r\n<\/pre>\n<p>Hey, we&#8217;ve come full circle! The only difference is that we used <code>enable_<wbr \/>shared_<wbr \/>from_<wbr \/>this<\/code> so that the <code>lambda_state<\/code> could obtain a <code>shared_ptr<\/code> to itself.<\/p>\n<p>Next time, we&#8217;ll translate all this nonsense into C# and JavaScript.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Explicit shared state.<\/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-108647","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Explicit shared state.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108647","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=108647"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108647\/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=108647"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108647"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108647"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}