{"id":93,"date":"2011-02-14T08:17:49","date_gmt":"2011-02-14T08:17:49","guid":{"rendered":"http:\/\/joose.it\/blog\/?p=93"},"modified":"2011-04-08T14:03:28","modified_gmt":"2011-04-08T14:03:28","slug":"joosex-cps-tutorial-part-i","status":"publish","type":"post","link":"http:\/\/joose.it\/blog\/2011\/02\/14\/joosex-cps-tutorial-part-i\/","title":{"rendered":"JooseX.CPS Tutorial &#8211; Part I"},"content":{"rendered":"<p>So, after the <a href=\"http:\/\/groups.google.com\/group\/joose-js\/browse_thread\/thread\/33ea67775c4ed845\">recent crack of our server<\/a>, the post about the <a href=\"http:\/\/samuraijack.github.com\/JooseX-CPS\/\">JooseX.CPS<\/a> was lost. It was poorly written anyway, so may be its even better that the server was hacked &#8211; because I&#8217;m writing a new post. JooseX.CPS is quite important extension, and its being extensively used in many other Joose-based projects, like KiokuDB, Syncler and Symbie. The new post is written in form of tutorial and contains a runnable code. At the end of this post you should grok the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Continuation-passing_style\">continuation passing style<\/a> :)<\/p>\n<h1>Setup<\/h1>\n<p>To follow this tutorial you will need:<\/p>\n<ul>\n<li><a href=\"http:\/\/nodejs.org\/#download\">NodeJS<\/a><\/li>\n<li><a href=\"http:\/\/npmjs.org\/\">npm<\/a><\/li>\n<li><a href=\"http:\/\/search.npmjs.org\/#\/task-joose-nodejs\">task-joose-nodejs<\/a><\/li>\n<\/ul>\n<p>The latter can be installed with `npm install task-joose-nodejs`.<\/p>\n<h1>Part I &#8211; Meet The Continuation<\/h1>\n<p>The tutorial will be split into 2 parts. In this part we&#8217;ll examine the low-level JooseX.CPS.Continuation class and its features. The second part will describe a JooseX.CPS trait itself, which provides a CPS sugar layer on top of JooseX.CPS.Continuation for you Joose classes.<\/p>\n<h1>Just try it, aka &#8220;Hello world&#8221;<\/h1>\n<p>Before we&#8217;ll dig in, lets see how the &#8220;hello world&#8221; will looks like in CPS world:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Hello')\r\n\r\n    this.CONT.CONTINUE()\r\n\r\n}).DELAY(1000).THEN(function () {\r\n\r\n    console.log('world!')\r\n\r\n}).now()<\/pre>\n<p>Try to launch this in your Node. You should see the following with 1s delay between the words:<\/p>\n<pre>nickolay@desktop:~\/Documents\/JooseBlog\/CPS-Tutorial$ node hello_world.js\r\nHello\r\nworld!<\/pre>\n<p>Compare with<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">console.log('Hello')\r\nconsole.log('world!')<\/pre>\n<p>You see the idea? With some additional boilerplate between them, the synchronous the statements work asynchronously, thats it. And as we&#8217;ll move forward in this tutorial, the amount of boilerplate will <em>reduce<\/em>, really.<\/p>\n<h1>Continuation anatomy<\/h1>\n<p>In the first approximation, continuation is an array of tasks, also containing the &#8220;catch&#8221; and &#8220;finally&#8221; functions:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">CONT = {\r\n\r\n    tasks           : [\r\n        {\r\n            func    : function doThis() { ... },\r\n            scope   : {},\r\n            args    : [ ... ]\r\n        },\r\n        {\r\n            func    : function doThat() { ... },\r\n            ...\r\n        },\r\n        ...\r\n    ],\r\n\r\n    catchFunc       : function () { ... },\r\n    finallyFunc     : function () { ... },\r\n}<\/pre>\n<p>The &#8220;task&#8221; is simply a function (mandatory), plus a scope for its execution and an array of arguments (both optional). Such continuation roughly corresponds to the following &#8220;synchronous&#8221; code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">try {\r\n\r\n    doThis()\r\n    doThat()\r\n\r\n} catch (e) {\r\n\r\n    cathcFunc(e)\r\n\r\n} finally {\r\n\r\n    finallyFunc()\r\n}<\/pre>\n<p><strong>Once more &#8211; continuation is a single &#8220;try\/catch&#8221; block, containing an array of tasks.<\/strong> You can add tasks to the continuation with the `TRY(func, scope, args)` method. Adding tasks <strong>will not launch them immediately<\/strong> &#8211; you need to &#8220;activate&#8221; the continuation manually with its method `now`.<\/p>\n<p>After activation, continuation will launch the first task. <strong>It will <em>embed<\/em> a new, fresh continuation instance into the scope of task, as the `this.CONT`.<\/strong> To pass the control flow from the 1st task to the next one, you need to call the `CONTINUE` method of the <em>embedded<\/em> continuation. <strong>Any parameters, passed to `CONTINUE` will be available as the arguments of the next task.<\/strong> Lets re-write the &#8220;Hello world&#8221; example, &#8220;by hands&#8221;:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nvar CONT    = new JooseX.CPS.Continuation()\r\n\r\nvar scope   = { toString : function () { return 'My scope' } }\r\n\r\nCONT.TRY(function () {\r\n    console.log(&quot;Current scope 1: %s&quot;, this)\r\n\r\n    console.log('Hello')\r\n\r\n    \/\/ a new, fresh instance of JooseX.CPS.Continuation has been embedded:\r\n    \/\/ this.CONT != CONT\r\n    this.CONT.CONTINUE('world', '!')\r\n\r\n}, scope)\r\n\r\nCONT.TRY(function (str1, str2) {\r\n    console.log(&quot;Current scope 2: %s&quot;, this)\r\n\r\n    console.log(str1, str2)\r\n})\r\n\r\nCONT.now()\r\n<\/pre>\n<p>Some sugar: there is `THEN` synonym for the `TRY` method, which sounds more naturally for the 2nd and further tasks. <strong>Note, that if you have not provided a scope for the task, it will be taken from the previous task.<\/strong><\/p>\n<p>The call to `CONTINUE` doesn&#8217;t have to be done synchronously, you can delay it. To do that, capture it to the closure with the `getCONTINUE` method. Lets add the 1s pause between the outputs, &#8220;manually&#8221; (w\/o the `DELAY()`)<strong>:<\/strong><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nvar CONT    = new JooseX.CPS.Continuation()\r\n\r\nvar scope   = { toString : function () { return 'My scope' } }\r\n\r\nCONT.TRY(function () {\r\n    console.log(&quot;Current scope 1: %s&quot;, this)\r\n\r\n    console.log('Hello')\r\n\r\n    \/\/ this.CONT != CONT - its a new, fresh instance of JooseX.CPS.Continuation\r\n    \/\/ passing the parameters further\r\n    this.CONT.CONTINUE('world', '!')\r\n\r\n}, scope)\r\n\r\nCONT.THEN(function (str1, str2) {\r\n\r\n    var CONTINUE = this.CONT.getCONTINUE()\r\n\r\n    setTimeout(function () {\r\n\r\n        CONTINUE(str1, str2)\r\n\r\n    }, 1000)\r\n})\r\n\r\nCONT.THEN(function (str1, str2) {\r\n    console.log(&quot;Current scope 2: %s&quot;, this)\r\n\r\n    console.log(str1, str2)\r\n})\r\n\r\nCONT.now()\r\n<\/pre>\n<p>Hey don&#8217;t scan, read the sources :)<\/p>\n<p>Instead of manual instantiation of JooseX.CPS you can use global `TRY` helper which just creates a new instance and delegates to its `TRY` method. And of course, the `TRY\/THEN` method return the continuation itself, so the calls can be chained. There is also a `DELAY` method and so we comes to the initial &#8220;Hello world&#8221;:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Hello')\r\n\r\n    this.CONT.CONTINUE()\r\n\r\n}).DELAY(1000).THEN(function () {\r\n\r\n    console.log('world!')\r\n\r\n}).now()<\/pre>\n<h1>Nesting<strong> <\/strong><\/h1>\n<p>Instead of calling the `CONTINUE` of the inner continuation, you can add a nested continuation &#8211; using `TRY` as usual. Keep in mind, that you need to activate it with `now`. When the last task of the nested continuation will call `CONTINUE` the control flow will continue on the outer level:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Hello')\r\n\r\n    this.CONT.DELAY(500).THEN(function () {\r\n\r\n        console.log(', ')\r\n\r\n        this.CONT.CONTINUE()\r\n\r\n    }).DELAY(500).THEN(function () {\r\n\r\n        this.CONT.CONTINUE('world')\r\n\r\n    }).now()\r\n\r\n}).THEN(function (str) {\r\n\r\n    console.log(str)\r\n\r\n}).now()<\/pre>\n<p>Pretty intuitive, don&#8217;t you think? Important note: <strong>once you&#8217;ve nested the continuation (instead of calling the `CONTINUE`) you must not call its `CONTINUE` method<\/strong> to <em>avoid the split of the control flow<\/em>. From this point, <strong>its the nested continuation responsibility to return the control flow<\/strong>.<\/p>\n<p>There is also a `RETURN` method to skip the other tasks from the current nesting level and return the control flow to the outer.<\/p>\n<h1>Exceptions<strong> <\/strong><\/h1>\n<p>We talked about the correspondence to the `try\/catch\/finally` block, and here&#8217;s their equivalent in the CPS. Surprisingly, they are named `TRY\/CATCH\/FINALLY` :) . Simplest case:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    throw &quot;oops&quot;\r\n\r\n}).CATCH(function (e) {\r\n\r\n    console.log(&quot;Exception caught: %s&quot;, e)\r\n\r\n    this.CONT.CONTINUE()\r\n\r\n}).FINALLY(function () {\r\n\r\n    console.log(&quot;Cleanup happens&quot;)\r\n\r\n}).now()<\/pre>\n<p>More text in bold: <strong>The `CATCH\/FINALLY` tasks are also &#8220;continued&#8221;. That is, to return the control flow from them you need to use `this.CONT.CONTINUE()` as in `TRY\/THEN`.<\/strong> This will allow you to write asynchronous exceptions handlers.<\/p>\n<h1>Nesting <em>and<\/em> Exceptions<\/h1>\n<p>The exceptions will correctly propagate from the nested continuations:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Hello')\r\n\r\n    this.CONT.DELAY(500).THEN(function () {\r\n\r\n        console.log(',')\r\n\r\n        throw &quot;world&quot;\r\n\r\n    }).DELAY(500).THEN(function () {\r\n\r\n        console.log(&quot;YOU SHOULD N'T SEE THIS TEXT&quot;)\r\n\r\n    }).now()\r\n\r\n}).CATCH(function (str) {\r\n\r\n    console.log(str)\r\n\r\n}).now()<\/pre>\n<p>they could be re-thrown just fine:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Hello')\r\n\r\n    this.CONT.DELAY(500).THEN(function () {\r\n\r\n        console.log(',')\r\n\r\n        throw &quot;f$$k&quot;\r\n\r\n    }).CATCH(function (str) {\r\n\r\n        throw &quot;polite&quot;\r\n\r\n    }).now()\r\n\r\n}).CATCH(function (str) {\r\n\r\n    console.log(str, &quot;world&quot;)\r\n\r\n}).now()\r\n\r\n<\/pre>\n<p>And in general, behaves very much like &#8220;usual&#8221; exceptions.<\/p>\n<h1>Show me the parallel<\/h1>\n<p>Of course any library for asynchronous control flow should provide the &#8220;parallel&#8221; mode. In JooseX.CPS you can activate it with `AND`:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Activated branch 1')\r\n\r\n    var CONTINUE = this.CONT.getCONTINUE()\r\n\r\n    setTimeout(function () {\r\n\r\n        console.log('world')\r\n\r\n        CONTINUE('!')\r\n\r\n    }, 1000)\r\n\r\n}).AND(function () {\r\n\r\n    console.log('Activated branch 2')\r\n\r\n    var CONTINUE = this.CONT.getCONTINUE()\r\n\r\n    setTimeout(function () {\r\n\r\n        console.log('Hello')\r\n\r\n        CONTINUE('!')\r\n\r\n    }, 500)\r\n\r\n}).THEN(function (res1, res2) {\r\n\r\n    console.log(res1[0], res2[0])\r\n\r\n}).now()\r\n\r\n<\/pre>\n<p>If you&#8217;ll run this code, you&#8217;ll\u00a0 see that branches were activated simultaneously, but the 2 final exclamation characters appears only after the branches gets merged. The very 1st task following the `AND` group receives the `arguments` objects passed to `CONTINUE` in the order of branches <em>declaration<\/em>.<\/p>\n<p>Of course, you can nest a new continuation into any of the branches:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">require('task-joose-nodejs')\r\n\r\nTRY(function () {\r\n\r\n    console.log('Activated branch 1')\r\n\r\n    this.CONT.CONTINUE('Branch 1 result')\r\n\r\n}).AND(function () {\r\n\r\n    console.log('Activated branch 2')\r\n\r\n    this.CONT.DELAY(500).THEN(function () {\r\n\r\n        console.log('The very long')\r\n\r\n        this.CONT.CONTINUE()\r\n\r\n    }).DELAY(500).THEN(function () {\r\n\r\n        console.log('asynchronous task')\r\n\r\n        this.CONT.CONTINUE()\r\n\r\n    }).DELAY(500).THEN(function () {\r\n\r\n        console.log('from several steps')\r\n\r\n        this.CONT.CONTINUE('Branch 2 result')\r\n\r\n    }).now()\r\n\r\n}).THEN(function (res1, res2) {\r\n\r\n    console.log(res1[0], res2[0])\r\n\r\n}).now()<\/pre>\n<h1>Some sugar<\/h1>\n<p>JooseX.CPS.Continuation also has lower-cased synonyms for the most used methods:<\/p>\n<ul>\n<li> THEN &#8211; then<\/li>\n<li> AND &#8211; and<\/li>\n<li> CATCH &#8211; except<\/li>\n<li> FINALLY &#8211; ensure<\/li>\n<\/ul>\n<p>Also, the `this.CONT.THEN( &#8230; ).now()` can be written as `this.CONT.andThen( &#8230; )`<\/p>\n<p>These synonyms simplifies a code a little bit and makes it more readable, but it still contain a lot of boilerplate. This boilerplate can be greatly reduced when using JooseX.CPS trait, which adds the &#8220;continued&#8221; methods to your class.<\/p>\n<p>It will be described in the part 2 of the tutorial, stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, after the recent crack of our server, the post about the JooseX.CPS was lost. It was poorly written anyway, so may be its even better that the server was hacked &#8211; because I&#8217;m writing a new post. JooseX.CPS is quite important extension, and its being extensively used in many other Joose-based projects, like KiokuDB, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[4,5],"tags":[12,16],"_links":{"self":[{"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/posts\/93"}],"collection":[{"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/comments?post=93"}],"version-history":[{"count":80,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/posts\/93\/revisions"}],"predecessor-version":[{"id":175,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/posts\/93\/revisions\/175"}],"wp:attachment":[{"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/media?parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/categories?post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/joose.it\/blog\/wp-json\/wp\/v2\/tags?post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}