@michael, integration-level javascript rarely deals with blocking-code.  its 
mostly tedious-work debugging and “fixing” endless piles of async-io timeout 
issues, without the help of a stack-trace :`(  and the term “fixing” is 
oftentimes euphemism for “rewriting the carefully architected backend into 
something simpler-and-dumber, because it turns out to have too many timeout 
issues during integration”.

you can’t seriously call yourself a senior-developer if you insist on using 
irrelevant blocking-code design-patterns like function-composition or 
pipeline-operators at such a level, which mostly gets in the way of your 
debugging and “fixing" tasks.  and using these features at the lower 
library-level only reinforce blocking-code-mindset bad-habits that will set you 
up for failure, when you're promoted to take on integration-level 
responsibilities.

btw, 2 of the async-steps in the example provided requires listening to 
triggered-events to proceed.  subjectively, the stack-overflow workaround i 
found for async/await to handle events [1] looks a bit more hacky and less 
clean than my example:

```
async function fn() {
  await a();
  await b();
  const [{data}, cResult] = await Promise.all([
    new Promise(resolve => thing.once('myEvent', resolve)),
    c()
  ]);
  return data;
}
```

but if you think you can create cleaner-code than what i posted using 
async/await, then feel free to try.

-kai

[1] 
https://stackoverflow.com/questions/43084557/using-promises-to-await-triggered-events
 
<https://stackoverflow.com/questions/43084557/using-promises-to-await-triggered-events>

> On Mar 16, 2018, at 8:35 AM, Michael J. Ryan <[email protected]> wrote:
> 
> Does the existence of a pipeline operator stop such code from working?
> 
> Frankly, I'd probably structure your example more as an async function...
> 
> -- 
> Michael J. Ryan - http://tracker1.info <http://tracker1.info/>
> 
> On Thu, Mar 15, 2018 at 9:22 AM, kai zhu <[email protected] 
> <mailto:[email protected]>> wrote:
> 
>> On Mar 15, 2018, at 10:49 PM, Michael J. Ryan <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>> And only 50x the amount of code too.
>> 
> 
> fair enough.  but lets move from small-picture toy-cases to bigger-picture 
> integration-level ones, where non-blocking code is common.
> 
> here's a working, simple but useful 40-sloc real-world electron-script [1] 
> which employs a single recursive-callback (function onNext()) to step-by-step 
> screen-capture websites/demos to png.  how would you re-express the 
> linear-steps in the example into something significantly more readable with 
> function-composition or pipeline-operators?
> 
> ```
> /*
>  * screen-capture.js
>  *
>  * this electron-script will screen-capture the website with the given url in 
> the commandline
>  *
>  * exsmple usage:
>  *    $ electron screen-capture.js https://www.pinterest.com/ 
> <https://www.pinterest.com/>
>  *
>  * output:
>  *    case 1: wait for electron to init
>  *    case 2: open url https://www.pinterest.com/ <https://www.pinterest.com/>
>  *    case 3: wait 5000ms for webpage to render
>  *    case 4: screenshot webpage
>  *    case 5: save file electron.screenshot.png
>  *    case 6: exit electron
>  */
> 
> /*jslint
>     bitwise: true,
>     browser: true,
>     maxerr: 8,
>     maxlen: 96,
>     node: true,
>     nomen: true,
>     regexp: true,
>     stupid: true
> */
> (function () {
>     'use strict';
>     var options, modeNext, onNext;
>     modeNext = 0;
>     onNext = function (data) {
>         modeNext += 1;
>         switch (modeNext) {
>         case 1:
>             console.log('case ' + modeNext + ': wait for electron to init');
>             // wait for electron to init
>             require('electron').app.once('ready', onNext);
>             break;
>         case 2:
>             console.log('case ' + modeNext + ': open url ' + process.argv[2]);
>             // init options
>             options = { frame: false, height: 768, width: 1024, x: 0, y: 0 };
>             // init browserWindow;
>             options.BrowserWindow = require('electron').BrowserWindow;
>             options.browserWindow = new options.BrowserWindow(options);
>             // goto next step when webpage is loaded
>             options.browserWindow.webContents.once('did-stop-loading', 
> onNext);
>             // open url
>             options.browserWindow.loadURL(process.argv[2]);
>             break;
>         case 3:
>             console.log('case ' + modeNext + ': wait 5000ms for webpage to 
> render’);
>             // wait 5000ms for webpage to render
>             setTimeout(onNext, 5000);
>             break;
>         case 4:
>             console.log('case ' + modeNext + ': screenshot webpage');
>             // screenshot webpage
>             options.browserWindow.capturePage(options, onNext);
>             break;
>         case 5:
>             console.log('case ' + modeNext + ': save file 
> electron.screenshot.png');
>             // save screenshot
>             require('fs').writeFile('electron.screenshot.png', data.toPng(), 
> onNext);
>             break;
>         case 6:
>             console.log('case ' + modeNext + ': exit electron');
>             // exit
>             process.exit(0);
>             break;
>         }
>     };
>     onNext();
> }());
> ```
> 
> [1] 
> https://github.com/kaizhu256/node-electron-lite#quickstart-screenshot-example 
> <https://github.com/kaizhu256/node-electron-lite#quickstart-screenshot-example>
> 
> <Screen-Shot-2018-03-15-at-11.59.33-PM-compressor.png>
> <Screen-Shot-2018-03-15-at-11.53.38-PM-compressor.png>
> 
>> On Mar 14, 2018 16:32, "kai zhu" <[email protected] 
>> <mailto:[email protected]>> wrote:
>>> On Mar 13, 2018, at 10:27 PM, Michael J. Ryan <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>> I'm jumping in late here, but being in that role, I can tell what it's 
>>> doing mostly by looking at it... It looks like and is a pipeline.  I 
>>> actually find that less confusing than deeply nested calls...  
>>> 
>>> a(b(c(d(e), f)))   
>>> 
>>> which I've seen in real code... vs
>>> 
>>> e |> d |> (r => c(r,f)) |> b |> a  
>>> 
>>> Which is a bit easier to reason with even if a little more verbose.  Each 
>>> step is in order instead of nesting which is reverse order.
>> 
>> 
>> 
>> @michael, i would argue a simple, magic-free, es5 recursive-callback of the 
>> following form is the easiest to read / debug / set-breakpoints-with:
>> 
>> ```js
>> var callbackState, recursiveCallback;
>> recursiveCallback = function (error, data) {
>>     // catch-all error-handler
>>     if (error) {
>>         ...
>>         return;
>>     }
>>     callbackState += 1;
>>     console.error('recursive-callback at case ' + callbackState);
>>     switch (callbackState) {
>>     case 1:
>>         dd(ee, recursiveCallback);
>>         break;
>>     // combine data with ff
>>     case 2:
>>         cc(data, ff, recursiveCallback);
>>         break;
>>     case 3:
>>         bb(data, recursiveCallback);
>>         break;
>>     case 4:
>>         aa(data, recursiveCallback);
>>         break;
>>     }
>> };
>> callbackState = 0;
>> recursiveCallback();
>> ```
>> 
>> here's the full, standalone, working example for your use-case (that’s both 
>> browser and nodejs compatible) with attached screenshot of it running in 
>> browser (and another one showing how easy it is to step-through and debug 
>> with only a single breakpoint).
>> 
>> ```
>> /*jslint
>>     bitwise: true,
>>     browser: true,
>>     maxerr: 8,
>>     maxlen: 256,
>>     node: true,
>>     nomen: true,
>>     regexp: true,
>>     stupid: true
>> */
>> 'use strict’;
>> var aa, bb, cc, dd, ee, ff, callbackState, recursiveCallback;
>> ff = 'goodbye world!';
>> ee = 'hello world!';
>> dd = function (data, recursiveCallback) {
>>     console.log('dd(ee) - simulating 300ms io-request with data=' + 
>> JSON.stringify(data) + ' ...');
>>     setTimeout(recursiveCallback, 300, null, data);
>> };
>> cc = function (data, data2, recursiveCallback) {
>>     console.log('cc(dd(ee), ff) - simulating 200ms io-request with data=' + 
>> JSON.stringify(data) + ' and data2=' + JSON.stringify(data2) +  ' ...');
>>     setTimeout(recursiveCallback, 200, null, data + ' ' + data2);
>> };
>> bb = function (data, recursiveCallback) {
>>     console.log('bb(cc(dd(ee), ff)) - simulating 100ms io-request with 
>> data=' + JSON.stringify(data) + ' ...');
>>     setTimeout(recursiveCallback, 100, null, data);
>> };
>> aa = function (data, recursiveCallback) {
>>     console.log('aa(bb(cc(dd(ee), ff))) - printing data ' + 
>> JSON.stringify(data));
>>     // simulate error
>>     recursiveCallback(new Error('this is a test error'));
>> };
>> 
>> 
>> 
>> recursiveCallback = function (error, data) {
>>     // catch-all error-handler
>>     if (error) {
>>         console.error('error occured in recursive-callback at case ' + 
>> callbackState);
>>         console.error(error);
>>         return;
>>     }
>>     callbackState += 1;
>>     console.error('recursive-callback at case ' + callbackState);
>>     switch (callbackState) {
>>     case 1:
>>         dd(ee, recursiveCallback);
>>         break;
>>     // combine data with ff
>>     case 2:
>>         cc(data, ff, recursiveCallback);
>>         break;
>>     case 3:
>>         bb(data, recursiveCallback);
>>         break;
>>     case 4:
>>         aa(data, recursiveCallback);
>>         break;
>>     }
>> };
>> callbackState = 0;
>> recursiveCallback();
>> 
>> /*
>> output:
>> 
>> recursive-callback at case 1
>> dd(ee) - simulating 300ms io-request with data="hello world!" ...
>> recursive-callback at case 2
>> cc(dd(ee), ff) - simulating 200ms io-request with data="hello world!" and 
>> data2="goodbye world!" ...
>> recursive-callback at case 3
>> bb(cc(dd(ee), ff)) - simulating 100ms io-request with data="hello world! 
>> goodbye world!" ...
>> recursive-callback at case 4
>> aa(bb(cc(dd(ee), ff))) - printing data "hello world! goodbye world!"
>> error occured in recursive-callback at case 4
>> Error: this is a test error
>>     at aa (/private/tmp/example.js:30:23)
>>     at Timeout.recursiveCallback [as _onTimeout] 
>> (/private/tmp/example.js:56:9)
>>     at ontimeout (timers.js:393:18)
>>     at tryOnTimeout (timers.js:250:5)
>>     at Timer.listOnTimeout (timers.js:214:5)
>> */
>> ```
>> 
>> <Screen-Shot-2018-03-15-at-6.35.47-AM-compressor.png>
>> <Screen-Shot-2018-03-15-at-7.21.03-AM-compressor.png>
>> 
>>> On Mar 14, 2018, at 7:19 AM, Alexander Jones <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>> Straw man. The problem is variables named h, f and g, not the use of a 
>>> composition operator.
>>> 
>>> On Sun, 11 Mar 2018 at 07:37, kai zhu <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> @peter, put yourself in the shoes of a senior-programmer responsible
>>> for overseeing an entire web-project.  the project is @ the
>>> integration-stage and you're busy debugging an async
>>> timeout/near-timeout bug preventing the frontend from talking to the
>>> backend (which btw, is one of the most common integration/qa
>>> javascript-bugs).
>>> 
>>> while trying to figure out what's causing the timeout-issue, you're
>>> debugging i/o code with operators that look like this:
>>> 
>>> ```
>>> const h = ? |> f |> g;
>>> ```
>>> 
>>> maybe it is useful for the small-picture sub-problem you were
>>> originally trying to solve. but now that you're a bigger-fish with
>>> bigger-picture integration i/o issues, doesn't this look alot like
>>> technical-debt that no one will have a clue how to debug once a month
>>> or two has passed?
>>> 
>>> -kai
>>> 
>>> On 3/11/18, Peter Jaszkowiak <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> > Oh please,
>>> >
>>> > This is an alternative syntax that's very useful for many people. If you
>>> > want too simplify syntax yourself you can use a linter to disable
>>> > alternatives.
>>> >
>>> > On Mar 10, 2018 22:56, "kai zhu" <[email protected] 
>>> > <mailto:[email protected]>> wrote:
>>> >
>>> >> my vote is for neither.  exactly what industry painpoint or
>>> >> problem-space do either of these proposals solve?
>>> >>
>>> >> rather, they compound an existing industry painpoint; where
>>> >> ocd-programmers have problems in deciding-and-choosing which es6
>>> >> style/design-pattern to employ and stick with before coding even
>>> >> begins. many of us wish there were less choices, like python (and a
>>> >> more assertive tc39 that makes clear certain proposals are
>>> >> productivity-negative and not open for debate) so we could get on with
>>> >> the actual coding-part.
>>> >>
>>> >> from a senior-engineer / technical-manager perspective, it also
>>> >> doesn't help in managing an entire web-project; comprised of dozens of
>>> >> sub-components that you didn't all write yourself; and having to
>>> >> context-switch for each sub-component's quirky es6/es7/es8/es9
>>> >> style-guide/design-pattern.
>>> >>
>>> >> On 3/4/18, Isiah Meadows <[email protected] 
>>> >> <mailto:[email protected]>> wrote:
>>> >> > Just thought I'd point out that the proposal itself entertains the
>>> >> > possibility of a corresponding composition proposal [1]. Also, in my
>>> >> > proposal, one of my "potential expansions" [2] would open a generic
>>> >> > door for "lifting" over a type, addressing the concern of
>>> >> > extensibility. (It's not ideal, and I just filed an issue in my repo
>>> >> > for that, but that's orthogonal.)
>>> >> >
>>> >> > [1]: https://github.com/tc39/proposal-pipeline-operator# 
>>> >> > <https://github.com/tc39/proposal-pipeline-operator#>
>>> >> related-proposals
>>> >> > [2]:
>>> >> > https://github.com/isiahmeadows/function-composition-proposal#possible-
>>> >> >  
>>> >> > <https://github.com/isiahmeadows/function-composition-proposal#possible->
>>> >> expansions
>>> >> >
>>> >> > -----
>>> >> >
>>> >> > Isiah Meadows
>>> >> > [email protected] <mailto:[email protected]>
>>> >> >
>>> >> > Looking for web consulting? Or a new website?
>>> >> > Send me an email and we can get started.
>>> >> > www.isiahmeadows.com <http://www.isiahmeadows.com/>
>>> >> >
>>> >> >
>>> >> > On Sat, Feb 24, 2018 at 5:40 AM, Naveen Chawla <[email protected] 
>>> >> > <mailto:[email protected]>>
>>> >> > wrote:
>>> >> >> Although it doesn't allow composition with generator functions like
>>> >> >> the
>>> >> >> composition proposal does, otherwise it's a pretty good solution.
>>> >> >>
>>> >> >> My only concern with pipeline is that since it offers a different way
>>> >> >> of
>>> >> >> calling functions than the `()` syntax, it can lead to mixed and hence
>>> >> >> slightly more confusing code when both `()` and `|>` are used. For
>>> >> example
>>> >> >> multi arg and no-arg functions would still use `()`, and single arg
>>> >> >> functions may or may not use `|>` depending on whether or not they may
>>> >> >> prospectively use a pipeline. The composition operator doesn't
>>> >> >> supersede
>>> >> >> the
>>> >> >> `()` syntax in any context, and so it could be argued it would lead to
>>> >> >> more
>>> >> >> consistent, more readable code.
>>> >> >>
>>> >> >> On Sat, 24 Feb 2018 at 15:02 Peter Jaszkowiak <[email protected] 
>>> >> >> <mailto:[email protected]>>
>>> >> wrote:
>>> >> >>>
>>> >> >>> I'd like to point out the partial application operator:
>>> >> >>> https://github.com/tc39/proposal-partial-application 
>>> >> >>> <https://github.com/tc39/proposal-partial-application>
>>> >> >>>
>>> >> >>> Sounds like the combination of pipeline + partial application would
>>> >> >>> result
>>> >> >>> in what is essentially the same as function composition operator:
>>> >> >>>
>>> >> >>> ```
>>> >> >>> const h = ? |> f |> g;
>>> >> >>> ```
>>> >> >>>
>>> >> >>> Which results in `h` being the composition `g • f`.
>>> >> >>>
>>> >> >>>
>>> >> >>> On Feb 24, 2018 02:21, "Naveen Chawla" <[email protected] 
>>> >> >>> <mailto:[email protected]>> wrote:
>>> >> >>>
>>> >> >>> That could be a problem for readability.
>>> >> >>> I agree with the rest of what you said.
>>> >> >>>
>>> >> >>>
>>> >> >>> On Sat, 24 Feb 2018 at 11:16 Viktor Kronvall <
>>> >> [email protected] <mailto:[email protected]>>
>>> >> >>> wrote:
>>> >> >>>>
>>> >> >>>> I don’t know the implications but I could easily imagine the
>>> >> >>>> pipeline
>>> >> >>>> proposal being extended to not taking any input on the left hand
>>> >> >>>> side
>>> >> >>>> and
>>> >> >>>> effectively represent composition in the opposite direction.
>>> >> >>>>
>>> >> >>>> For example:
>>> >> >>>> ```
>>> >> >>>> let h = |> f |> g
>>> >> >>>> h(2) //g(f(2))
>>> >> >>>> ```
>>> >> >>>>
>>> >> >>>> That said, the point holds for the proposal in its current state.
>>> >> Being
>>> >> >>>> able to compose functions
>>> >> >>>> leads to much more expressivity than if you have
>>> >> >>>> to call the pipeline (and collapse) where it is defined.
>>> >> >>>> 2018年2月24日(土) 14:32 Naveen Chawla <[email protected] 
>>> >> >>>> <mailto:[email protected]>>:
>>> >> >>>>>
>>> >> >>>>> The function composition operator composes function pipelines into
>>> >> >>>>> functions for later use and/or further composition. Those functions
>>> >> >>>>> still
>>> >> >>>>> need to be called via the existing `()` syntax, so it doesn't offer
>>> >> >>>>> a
>>> >> >>>>> different way of calling functions as such.
>>> >> >>>>>
>>> >> >>>>> The function pipeline operator calls the function pipeline
>>> >> immediately,
>>> >> >>>>> so it is really only a different way of calling functions.
>>> >> >>>>>
>>> >> >>>>> On Fri, 23 Feb 2018 at 12:37 Jordan Harband <[email protected] 
>>> >> >>>>> <mailto:[email protected]>>
>>> >> wrote:
>>> >> >>>>>>
>>> >> >>>>>> How is either operator not "a different way of calling functions"?
>>> >> >>>>>>
>>> >> >>>>>> On Thu, Feb 22, 2018 at 8:34 PM, Naveen Chawla <
>>> >> [email protected] <mailto:[email protected]>>
>>> >> >>>>>> wrote:
>>> >> >>>>>>>
>>> >> >>>>>>> I was just thinking about the relative merits and coexistence (or
>>> >> >>>>>>> not)
>>> >> >>>>>>> of function composition operator and function pipeline operator
>>> >> >>>>>>> features:
>>> >> >>>>>>>
>>> >> >>>>>>> e.g.
>>> >> >>>>>>>
>>> >> >>>>>>> https://github.com/TheNavigateur/proposal-pipeline-operator-for- 
>>> >> >>>>>>> <https://github.com/TheNavigateur/proposal-pipeline-operator-for->
>>> >> function-composition
>>> >> >>>>>>> https://github.com/tc39/proposal-pipeline-operator 
>>> >> >>>>>>> <https://github.com/tc39/proposal-pipeline-operator>
>>> >> >>>>>>>
>>> >> >>>>>>> They can of course co-exist, but there is overlap only in the
>>> >> respect
>>> >> >>>>>>> that both allow function pipelines to be called from left to
>>> >> >>>>>>> right
>>> >> >>>>>>> (except
>>> >> >>>>>>> the input parameter in the case of the composition feature, which
>>> >> >>>>>>> requires
>>> >> >>>>>>> existing bracket syntax to be used to call it). If one were to be
>>> >> >>>>>>> chosen,
>>> >> >>>>>>> would say that a function composition operator adds a whole new
>>> >> >>>>>>> dimension of
>>> >> >>>>>>> expressive power to the language, whereas a pipeline operator
>>> >> >>>>>>> only
>>> >> >>>>>>> offers a
>>> >> >>>>>>> different way of calling functions.
>>> >> >>>>>>>
>>> >> >>>>>>> I was wondering about all of your thoughts about whether you'd
>>> >> prefer
>>> >> >>>>>>> only the pipeline operator, only the composition operator, or
>>> >> >>>>>>> both,
>>> >> >>>>>>> or
>>> >> >>>>>>> neither to be added to the language (these are pretty much all
>>> >> >>>>>>> the
>>> >> >>>>>>> possibilities), and why.
>>> >> >>>>>>>
>>> >> >>>>>>> _______________________________________________
>>> >> >>>>>>> es-discuss mailing list
>>> >> >>>>>>> [email protected] <mailto:[email protected]>
>>> >> >>>>>>> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> >>>>>>> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >>>>>>>
>>> >> >>>>>>
>>> >> >>>>> _______________________________________________
>>> >> >>>>> es-discuss mailing list
>>> >> >>>>> [email protected] <mailto:[email protected]>
>>> >> >>>>> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> >>>>> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >>>
>>> >> >>>
>>> >> >>> _______________________________________________
>>> >> >>> es-discuss mailing list
>>> >> >>> [email protected] <mailto:[email protected]>
>>> >> >>> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> >>> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >>>
>>> >> >>>
>>> >> >>> _______________________________________________
>>> >> >>> es-discuss mailing list
>>> >> >>> [email protected] <mailto:[email protected]>
>>> >> >>> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> >>> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >>
>>> >> >>
>>> >> >> _______________________________________________
>>> >> >> es-discuss mailing list
>>> >> >> [email protected] <mailto:[email protected]>
>>> >> >> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> >> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >>
>>> >> > _______________________________________________
>>> >> > es-discuss mailing list
>>> >> > [email protected] <mailto:[email protected]>
>>> >> > https://mail.mozilla.org/listinfo/es-discuss 
>>> >> > <https://mail.mozilla.org/listinfo/es-discuss>
>>> >> >
>>> >> _______________________________________________
>>> >> es-discuss mailing list
>>> >> [email protected] <mailto:[email protected]>
>>> >> https://mail.mozilla.org/listinfo/es-discuss 
>>> >> <https://mail.mozilla.org/listinfo/es-discuss>
>>> >>
>>> >
>>> _______________________________________________
>>> es-discuss mailing list
>>> [email protected] <mailto:[email protected]>
>>> https://mail.mozilla.org/listinfo/es-discuss 
>>> <https://mail.mozilla.org/listinfo/es-discuss>
>> 
> 
> 

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to