{"id":93092,"date":"2016-02-26T07:00:00","date_gmt":"2016-02-26T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=93092"},"modified":"2019-03-13T10:30:50","modified_gmt":"2019-03-13T17:30:50","slug":"20160226-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20160226-00\/?p=93092","title":{"rendered":"Changing a loop into a promise or task chain"},"content":{"rendered":"<p>If you are dealing with PPL Tasks in C++ or Promises in JavaScript, you run into the problem of having to rephrase loops in the form of callbacks. (On the other hand, if you&#8217;re using Tasks in C#, then you have the wonderful <code>await<\/code> keyword to do this all for you. If you&#8217;re a JavaScript programmer, <a HREF=\"http:\/\/www.joezimjs.com\/javascript\/synchronizing-asynchronous-javascript-es7\/\">you can look at the <code>async<\/code> keyword coming to ES7<\/a>. If you are using <a HREF=\"http:\/\/blogs.msdn.com\/b\/vcblog\/archive\/2013\/12\/20\/asynchronous-programming-in-c-using-resumable-functions-and-await.aspx\">C++ resumable functions<\/a>, then you can use <code>__await<\/code>. <a HREF=\"http:\/\/blogs.msdn.com\/b\/vcblog\/archive\/2014\/11\/12\/resumable-functions-in-c.aspx\">More about resumable functions<\/a>. <a HREF=\"http:\/\/blogs.msdn.com\/b\/vcblog\/archive\/2015\/04\/29\/more-about-resumable-functions-in-c.aspx\">Still more<\/a>. ) <\/p>\n<p>Let&#8217;s convert a loop into a promise\/task chain. Here&#8217;s the loop: <\/p>\n<pre>\nstd::vector&lt;std::unique_ptr&lt;Thing&gt;&gt; things;\n\nvoid FrobEachThing()\n{\n    for (auto thing : things) {\n       thing-&gt;FrobAsync();\n    }\n}\n<\/pre>\n<p>The problem is that the <code>Frob&shy;Async<\/code> method is asynchronous and returns a task, and we want to perform each frob operation in series, not in parallel. If we were writing in C#, this would be a piece of cake: <\/p>\n<pre>\nasync Task FrobEachThingAsync()\n{\n    foreach (var thing in things) {\n        await thing.FrobAsync();\n    }\n}\n<\/pre>\n<p>Similarly, if we had resumable functions: <\/p>\n<pre>\ntask&lt;void&gt; FrobEachThingAsync()\n{\n    for (auto thing : things) {\n       __await thing-&gt;FrobAsync();\n    }\n}\n<\/pre>\n<p>But we don&#8217;t have that, so we will need to do the transformation ourselves. <\/p>\n<p>At this point, you think back to Computer Science class and that stuff you learned about recursion and you wondered when anybody would ever want to do that. Well, we&#8217;re going to do that. <\/p>\n<p>The idea is that we start the asynchronous operation, and pass as a callback a function that knows how to continue the loop. Since this is a loop, the callback may end up passing itself as the next callback, and that&#8217;s where we get the appearance of recursion. (It&#8217;s not really recursion because the creation of the task returns immediately; the callback runs when the task completes, which is some time later.) <\/p>\n<p>First, let&#8217;s write out what that ranged for loop really means:<\/p>\n<pre>\nvoid FrobEachThing()\n{\n    auto first = begin(things);\n    auto last = end(things);\n    while (first != last) {\n        (*first)-&gt;FrobAsync();\n        first++;\n    }\n}\n<\/pre>\n<p>With this formulation, it&#8217;s easier to see how to make it recursive. Actually, the important thing is that you make it <i>tail-recursive<\/i>. <\/p>\n<pre>\ntypedef decltype(begin(things)) thing_iterator;\n\nvoid FrobTheRestOfTheThings(\n    thing_iterator first,\n    thing_iterator last)\n{\n    if (first != last) {\n        (*first)-&gt;FrobAsync();\n        FrobTheRestOfTheThings(first + 1, last);\n    }\n}\n\nvoid FrobEachThing()\n{\n    FrobTheRestOfTheThings(begin(things), end(things));\n}\n<\/pre>\n<p>Now that we have tail recursion, we can make it into a task chain: <\/p>\n<pre>\ntask&lt;void&gt;\nFrobTheRestOfTheThingsAsync(\n    thing_iterator first,\n    thing_iterator last)\n{\n    if (first != last) {\n        return (*first)-&gt;FrobAsync().then([first, last]() {\n            return FrobTheRestOfTheThingsAsync(first + 1, last);\n        });\n    } else {\n        return create_task([](){}); \/\/ null task - base case of recursion\n    }\n}\n\ntask&lt;void&gt; FrobEachThingAsync()\n{\n    return FrobTheRestOfTheThingsAsync(begin(things), end(things));\n}\n<\/pre>\n<p>The same logic applies to JavaScript. Starting with <\/p>\n<pre>\nfunction frobEachThing()\n{\n    things.forEach(function(thing) { thing.Frob(); });\n}\n<\/pre>\n<p>First, do the rewrite into an explicit loop. <\/p>\n<pre>\nfunction frobEachThing()\n{\n    var i = 0;\n    while (i &lt; things.length) {\n        things[i].frob();\n        i++;\n    }\n}\n<\/pre>\n<p>Then apply the same logic as above to convert this into a promise chain: <\/p>\n<pre>\nfunction frobTheRestOfTheThingsAsync(array, index, length) {\n    if (index != length) {\n        return array[index].frobAsync().then(function() {\n            return frobTheRestOfTheThingsAsync(array, index + 1, length);\n        });\n    } else {\n        return WinJS.Promise.wrap(); \/\/ null task - base case of recursion\n    }\n}\n\nfunction frobEachThingAsync()\n{\n    return FrobTheRestOfTheThingsAsync(things, 0, things.length);\n}\n<\/pre>\n<p>JavaScript captures by reference and uses garbage collection, so things are a bit easier. We can make one function local to the other and let the closures capture our state. <\/p>\n<pre>\nfunction frobEachThingAsync()\n{\n    var array = things;\n    var length = array.length;\n    var index = 0;\n\n    function rest() {\n        if (index != length) {\n            return array[index].frobAsync().then(function() {\n                index++;\n                rest();\n            });\n        } else {\n            return WinJS.Promise.wrap(); \/\/ null task - base case of recursion\n        }\n    }\n\n    return rest();\n}\n<\/pre>\n<p><b>Bonus reading<\/b>: <a HREF=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2012\/05\/09\/how-to-put-a-ppltasks-continuation-chain-into-a-loop.aspx\">How to put a PPLTasks continuation chain into a loop<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Crack open your textbooks.<\/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-93092","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Crack open your textbooks.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93092","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=93092"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/93092\/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=93092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=93092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=93092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}