notoriousb1t

JS Pipeline Operator

I was reading through Reddit the other night and came across a feature being considered for JavaScript. The feature in question is a new operator |> to pipe together functions.

Some code samples...

A compulsory math example

    function square(n) {
      return n * n;
    }
    function double(n) {
      return n * 2;
    }

    // outputs 50 to the console
    5 |> square |> double |> console.log;

An arbitrary string decorator example

    function toUpperCase(str) {
      return (str || '').toUpperCase();
    }
    function toPossessive(str) {
      return str + "'s";
    }

    // outputs TIM'S to the console
    "Tim" |> toPossessive |> toUpperCase |> console.log;

The "next" Gulp

    const concat = require('slurp-concat');
    slurp.task('scripts', () => 
        slurp.src('./lib/*.js')
        |> concat('all.js')
        |> slurp.dest('./dist/')
    );

For more examples, here is the full proposal for ES7.

Thoughts

On one hand, adding this operator would provide a more natural way to write functional applications. The form, from left to right, would make it easier to read out loud. If I read the code sample above out loud I would say, "Use 5, then square, double, and log it to the console."

On the other hand, it would add yet another way to do something in the language. JavaScript has enough expressivity for two languages. We could accomplish the same thing by adding a .pipe function to Object and chaining calls like so 5.pipe(square).pipe(double).pipe(console.log). This could be easily polyfilled.

The proposal does show a couple of interesting examples in how it could positively impact promises and validation, but I think that the piping would be better if it was lazy. If you call 5 |> console.log, it does that immediately. I think that the pipeline operator should instead return a function. This way, you can use it to chain functions passed as callbacks. For example

A compulsory math example (but way lazier)

    function square(n) {
      return n * n;
    }
    function double(n) {
      return n * 2;
    }

    // a composite, reusable function
    var squareDoubleAndLog = square |> double |> console.log;

    // outputs 50 to the console
    squareDoubleAndLog(5);

Composing filters naturally

    // convert to number
    function toNumber(s) {
        return Number(s);
    }

    // return true if number is a power of two
    function isPowerOfTwo(n) {
        return n % 2 === 0;
    }

    // numbers to evaluate
    var ns = ['0.5', '1', '4', '3.5', '10.2345'];

    // prints 4, 3.5, 10.2345
    ns.filter(toNumber |> Math.round |> isPowerOfTwo)
        .forEach(console.log);

I think that we would really benefit from a lazy version of |> instead because it would encourage composing functions in a chain.