74 comments

[ 3.0 ms ] story [ 144 ms ] thread
I liked this feature in LiveScript rather much.

Especially that it worked in both directions.

    my-list = filter <| sort <| get-data
Doesn't LiveScript already have it ?
As noted in the OP, yes, as do F#, Elixir, Elm and Julia.
Can we just put more focus on sweet.js so we can do this kind of in a library with standard build tooling? http://sweetjs.org/

There's a lot more operators than |> that you would want. Clojure commonly uses ->, ->>, as->, etc. It should be done in a library if it is done at all.

Also, going full-on functional in javascript is going to end badly, javascript simply wasn't designed for it. If you go down this path in real projects, sooner or later you inevitably end up at clojurescript or whatever other real FP language suits.

Can you elaborate on the rough seams between JavaScript and "full on functional"?

I'm not a believer in the FP vs. OO religion, and have historically been skeptical of the bind operator. That said, I think that both composition via objects and composition via functions have their place.

The pipeline operator attempts to make composition via functions more readable (left-to-right instead of right-to-left) and unless you think composition via functions is a bad idea in JS in all cases, I'm not sure what "full-on functional" has to do with it.

js objects are mutable; utliliy libraries like underscore, lodash, jquery, do not provide purity guarantees, they export impure functions that mutate objects (e.g. https://lodash.com/docs#merge). When we start leaning heavily on function composition to build our abstractions, we simply must have purity guarantees for everyday utilities or everything falls apart. So to go "full-on functional" in javascript means we need to fork and rewrite the entire ecosystem. And if you're going to do that, there isn't much value in keeping javascript.
So we need an (a) method to freeze object and it children, (b) to indicate that function will accept and/or return only read-only objects. Reserved "const" keyword is perfect for that.
That's unfortunately not what es6 const does - const is about re-assignment, not about immutability. (Though you can implement immutability in terms of non-re-assinment if it is const-all-the-way-down, which javascript objects aren't.) And you still need to re-write all the ecosystem to work with immutable objects.
Are purity checks that hard to implement?

I don't know much about this...

Check that the function only writes on local variables and only reads closure variables and only calls other pure functions.

I think maybe he means that it is not idiomatic. It doesn't feel like JS with the proposed Ruby-like new bind syntax and now with this Unix-flavored pipeline operator, the language is taking on a new identity that some may not like.
Briefly, you can look at it through the prism of equality.

In javascript, 1 === 1, and "foo" === "foo". However, [] !== [] and {} !== {}. This is because in Javascript, like in Java, there is a distinction between value types (essentially, simple primitive values like numbers and strings) and reference types (collections - arrays and objects). When you assign an array to a variable, you are actually pointing the variable to a reference to the array. As a mutable data structure, its identity is more important than its value: it is expected that you shall be calling push, etc, and thus changing its value in place.

In Clojure (for example), (= 1 1) and (= "foo" "foo") and (= [] []) and (= {} {}). Because Clojure's data structures are immutable, the idea of checking for identity is almost meaningless (although you can, with the identical? function). In an FP style, with generic but immutable data structures, we are more interested in value equality, since we are not concerned so much with objects with a long lifecycle over which the values of their fields may change.

Javascript is in an odd position - it has enough features for both traditional OO and functional programming styles to be possible, but the two do not easily co-exist. Compromises are necessary. So, if our program is composed of mostly pure functions operating on generic data structures, we must do a lot of defensive copying, and use library functions for deep equality, because the data structures are not designed for this usage.

This is not to say it's infeasible to program in this way in Javascript: it is, and I try to. But a language designed from the ground up for functional programming will point you more enthusiastically in that direction than JS does.

On topic: like the syntax!

(you're replying to the guy who wrote Ember.js)
I totally didn't see that. Usernames are too small on this damn website.
I like this a lot. It's similar to the proposed function bind syntax[1], but a bit more friendly to not-`this`-related use:

    function bindMap(fn) { return this.map(fn) }
    [ 1, 2, 3 ]::bindMap(n => n + 1)
    // standalone use: bindMap.call(arr, fn)

    function pipelineMap(fn) { return arr => arr.map(fn) }
    [ 1, 2, 3 ] |> pipelineMap(n => n + 1)
    // standalone use: pipelineMap(fn)(arr)
(Also nice that it works in a very similar way to decorators, although they won't be interchangeable in most cases, with decorators working on class constructors and property descriptors, instead of just any value.)

Presumably, at most one of these proposals will make it in :)

[1]: https://github.com/zenparsing/es-function-bind

I agree that a "functional" operator that uses `this` as the first argument is weird.

The main goal of all of these proposals is "left to right" composition when working with functions, and functions take parameters.

In concatenative languages, this style of composition is the norm, and it does indeed work well for many tasks:

http://concatenative.org/wiki/view/Pipeline%20style

It is available in JS too:

    function double(str) {
      return str+', '+str;
    }
    function ucase(str) {
      return str.slice(0,1).toUpperCase()+ str.slice(1);
    }
    function exclamation(str) {
      return str+"!";
    }
    
    var _="hello";
    _ = double(_);
    _ = ucase(_);
    // _ = foo(_);
    _ = exclamation(_);
    
    console.log(_); // Hello, hello!
    
    function pipe() {
      var functions=[];
      for(var i=0; i<arguments.length; i++) {
        functions[i]=arguments[i];
      }
      return function pipe_call(arg) {
        for(var i=0; i<functions.length; i++) {
          arg=functions[i](arg);
        }
        return arg;
      }
    }
    
    var _="hello";
    _ =pipe(
      double,
      ucase,
      // foo,
      exclamation
    )(_);
    console.log(_); // Hello, hello!
I feel like that just confuses things for no good reason. It's no fewer characters than parens but provides as I see it less clarity.
I think the clarity comes from the reading order. str |> method1 |> method2 |> method3 vs method3(method2(method1(str))).
That's readable in the simple case, (arg1 is a string, returns a string). What about the more complex cases? Different method signatures, required extra arguments, returning objects or arrays? This will either a) break in those cases, or b) not be applicable. In which case, it's extra complexity for very little gain.

Seriously, this just seems like syntax sugar that just isn't needed. I get that you might not think it's elegant, but is anyone seriously troubled or confused by method3(method2(method1(str)))? How would the pipeline syntax help here?

Yep; same reason Lodash implements _.flow and _.compose.

It also encourages you to write methods that take a single argument and return a single value, or partially apply those that don't.

How it's "less clarity"?

What happens is much easier to read if you know what the operator means.

The only way the old way has more clarity is in the "we are already familiar with it" way. In any other way, this method trumps it.

It's much less clear than the F# and Elixir versions of |> are, so if you've used those languages this feels confusing looking. It would be nice to introduce |> into Javascript while keeping it just as understandable as it is in every other language that already has it.
What's so painful about just doing `exclaim(capitalize(doubleSay("hello")));`? Why introduce needless syntactic sugar that'll only confuse people about how UNIX pipes work?
To understand the nesting you have to evaluate the functions in the opposite order than you're reading them:

exclaim capitalize doubleSay

Sure, some of us has spent 20 years doing this so it's easy, but you can't deny that this is far nicer to read:

doubleSay capitalize exclaim

I'm a big fan of Fluent Interfaces, so I use this construct fairly often:

"hello".doubleSay().capitalize().exclaim()

This should be how it's done, simplistic, nothing new to learn, easy to read.
Because that's a terrible code smell! The proper way to handle that case in a language which doesn't support pipelining would be to break each call into a variable and use those those variables. But even that can be tedious, hence the pipelining operators which have cropped up in some languages.
it's very common in javascript to have chained methods, to be able to do things like

    _(array)
    .compact()
    .map(function(x) {
       return x * x;
    })
    .filter(function(x) {
        return x > 100;
    }).value()
(example from underscore/lodash)

The problem with this is to be able to add a custom function to this pipeline, you have to extend the prototype of the library with your own functions, or re-implement it.

Extending the prototype is considered bad practice for a lot of reasons, for example due to polluting code in other modules or upstream changes breaking your code.

If instead of chaining methods we chained functions we are left with this awkward syntax:

    custom(filter(map(compact(array), function(x) {
         return x * x;
    }), function(x) {
         return x > 100;
    }));
it's much cleaner to write it like this:

    compact(arr)
    |> map(function(x) {
        return x * x;
    })
    |> filter(function(x) {
        return x > 100;
    })
    |> custom
The linked page has a nice example and explanation about this concerning promises https://github.com/mindeavor/es-pipeline-operator#sample-usa...
> The problem with this is to be able to add a custom function to this pipeline, you have to extend the prototype of the library with your own functions, or re-implement it.

That's exactly what transducers try to solve, and fortunately they do exist for js (http://jlongster.com/Transducers.js--A-JavaScript-Library-fo...) where processing of individual elements is separated from plumbing, so you can add your own custom computation in the chain. It even has pretty good performances (http://jlongster.com/Transducers.js-Round-2-with-Benchmarks), all with the standard data structures !

Of course transducers are useful only when you want to transform data, not when you want to act on them in the chain.

(comment deleted)
Please no.

Javascript's beauty lies in its versatile simplicity. Can we just leave these sorts of things to systems programming languages like C++? I came to javascript because of its lack of cruft, but if libraries start adopting this then I'll be forced to put it in my code as well. If that happens then I'll probably leave for nim or clojure, though that's not preferable.

Can't speak for nim, but Clojure has a near-exact feature which is used all over the place, the thread-first and thread-last macros.

Example:

    (defn do-stuff [params-map]
       (->
          (build-object params-map)
          (do-thing-with-object)
          (extract-thing)
          (format-thing)))
I'm not sure why you'd choose Clojure to get away from things like |>.
Clojure is a functional language, so it meshes well with the rest of the syntax, but in javascript's case it's just syntax bloat. It's going to be really jarring in the middle of regular imperative code, and it's not going to be too far removed from

  cout << "foo";
Whether `|>` would mesh with your code depends on the code that's already there.

Doesn't seem fair to shut down this proposal because you happen to write and work with imperative code, a style that Javascript and modern abstractions are moving away from.

In fact, the Javascript hack to get a pipeline-like style is to make some opaque wrapper object that you can chain method calls onto like `_.chain(a).b().c().d().value()` in Lodash, when all you wanted was a chain of function application.

`|>`, `<|`, composition operators, and friends would all be welcome complements to the Javascript code bases I've worked with in the last few years.

# Why not ## Lodash `_.flow(b,c,d)(a)` // left to right `_.compose(d,c,b)(a)` // right to left `_.flowRight(d,c,b)(a)` // right to left `_.backflow(d,c,b)(a)` // right to left

## RamdaJS `_.pipe(b,c,d)(a)` // left to right

# But why are we inventing so many ways of doing forward, backward function application and composition.

Aside: I've never found an application of lodash `_.chain` that couldn't be expressed in a better way.

Elixir has this exact feature. I'm sure it's not the first language to either.
F#/OCaml too, probably all the ML variants actually.
C++ has a piping operator?

    attrs
        |> bounded('age', 1, 100)
        |> format('name', /^[a-z]$/i)
        |> Person.insertIntoDatabase
This reminds me of those "Perl Poetry" code snippets from 2001.
Yes, and we all know how that turned out with Perl. I don't think Perl is necessarily a good model for readable code.

This seems to me to be a case of "just because we can, doesn't mean we should."

There are a lot of programmers coming from other functional programming languages to Javascript, bringing a lot of ideas from their own language to "make Javascript better".

On top of that, there are also "transpiler folks": Ruby |> CoffeeScript, C#/F# |> TypeScript, etc...

The classical Javascript programmer might be the last of a dying breed.

This is syntactic sugar not cruft. They're not proposing to add any new functionality to what we already have.
If we're going to do this operator, I would prefer a regular arrow:

    import { sortBy, filter, map } from 'array-like';

    let names = document.querySelectorAll('.entry')
      -> sortBy('title')
      -> filter(entry => entry.getAttribute('data-url') in whitelist)
      -> map(entry => entry.getAttribute('name');
I personally find this more readable than either the bind proposal (which looks too much like a property access, and not enough like a function call, to me) and the proposed pipeline operator, which doesn't have an immediate meaning to my eyes.
That said, the main counterargument to this proposal is that it's already possible to get "left to right" composition in userland without this operator, as underscore shows.

The main counterargument to "do it like underscore" is that underscore still ends up being an object whose methods are added to a prototype, not imported.

The benefit of the "pipeline" or "bind" approach is that you get left-to-right composition while still importing the names you're using.

> I personally find this more readable than ... the proposed pipeline operator, which doesn't have an immediate meaning to my eyes.

Really? have you never seen unix pipes?

I would find pipes to be very readable (but the single pipe operator is taken). The triangle isn't immediately an analogy to "unix pipes".
that won't play nice with coffeescript!
CoffeeScript should have thought of that ;)
JS

  var result = exclaim(capitalize(doubleSay("hello")));
ES7 Proposal: The Pipeline Operator

  var result = "hello"
    |> doubleSay
    |> capitalize
    |> exclaim;
CoffeeScript

  result = exclaim capitalize doubleSay 'hello'
I'll take CoffeeScript.
Why the arrow? That works just fine with a dot.

  let names = document.querySelectorAll('.entry')
                      .sortBy('title')
                      .filter(entry => entry.getAttribute('data-url') in whitelist)
                      .map(entry => entry.getAttribute('name');
Only if those methods are added to NodeList, which they haven't been.

(and of course 'sortBy' is nonstandard)

Of course, but you can extend the underlying type. But I can see why you wouldn't want to do that over and over for all collection types. There is probably a tradeoff between reusing the established dot syntax and having a different syntax to be explicit about invoking a non-member function.
> I would prefer a regular arrow

And I want it painted green ;-)

> ... which doesn't have an immediate meaning to my eyes.

It's a matter of background. F#, Julia and Livescript have identical operators, likely among others.

https://msdn.microsoft.com/en-us/library/dd233229.aspx#Ancho...

http://docs.julialang.org/en/release-0.4/stdlib/base/?highli...

http://livescript.net/#piping

Fair enough.

I personally consider compound operators (asymmetrical) to be pretty risky (the do, indeed, depend on background), and I like '->' because it has a clear meaning outside of programming.

But you're right, this is a bikeshed.

I'd prefer either version of the pipeline operator to bind.

an Array.from will make it possible to do it like regular arrays. I don't see a good use case for this operator really.
I bet Lispers would beg to differ. :D

Nested function do one thing on a chunk of data, then another, then another.

*nix pipelines apply all the filters at once and control the scheduling and lifetime of the filters.

Those are quite different concepts, and I think it's confusing to conflate the two. Plus every decent editor can handle paired parentheses.

    > I bet Lispers would beg to differ. :D
Would they?

I wrote and read threading macros all the time when I used Clojure. Turns out it cleans up code.

I think you meant many_parens(too(as(thing(a(such(is(there(because)))))))).
I don't entirely understand where this gets me that promises don't.
Promises are an abstraction for managing asynchronous operations.

This proposal is about function application.

The single-argument case is elegant, and the multiple-argument case is awful.

    var newScore = add(7, validateScore( double(person.score) ))
becomes

    var newScore = person.score
      |> double
      |> score => add(7, score)
      |> validateScore
This is very Forth-like. Operands get pushed on the stack, and operators take from the stack and push results back. In Forth, there's no operator precedence and no parentheses; it's pure reverse Polish.

Why not go all the way to pure RPN?

     7 person score . double ValidateScore add newScore = 
See how it simplifies the syntax? Of course, you have to know how many arguments each function takes.

Do we really want to go down this route? It's all syntax; it doesn't add any capability. As an extension to an existing language, it's likely to produce a mess.

Mixing functional and imperative notations is a problem. LISP is all nested parentheses, and that bothered a lot of people. Forth eliminates all the parentheses, which bothered different people. Python was pure imperative, ("lambda" went in over major objections) and is gradually getting more functional features, but they don't fit the syntax well.

This essentially exists - extension methods.
Extension methods only apply to instances and they must be declared explicitly.

This syntax can be used anywhere as long as the types signatures of the functions are conducive to the chaining.

Not sure what you mean with applying only to instances, in which case couldn't you use an extension method? If you own the code making a function an extension method seems not a big deal. If you want to invoke a static function you don't own the code for then you could have a generic wrapper extension method which admittedly would probably look rather clumsy and nullify the desired gain in readability.
But you have to write them before using. It's not needed in case of the discussed feature.
After having used this operator in Elixir and Elm, I would love to see it in JS. I know it seems like a superficial issue, but I think the left-to-right chaining flow is one of the main things people miss as they move from an OO style to a more functional one.
It is not superficial or trivial at all. This proposal helps to ease the cognitive load required when reading or debugging code at least for the straightforward cases and makes writing code even more interesting and intuitive.
@dang, was this manually penalized? Or is it a false positive to the flamewar detector?

It looked like a fine submission.

52 points, an hour ago, and it lies on the third page...

If is to be more functional like e prefer add functions: compose and curry:

1 - // With pipe: var result = "hello" |> doubleSay |> capitalize |> exclaim;

  With compose:
  var greet = compose(exclaim, capitalize, doubleSay);
  greet("hello");
  // or compose(exclaim, capitalize, doubleSay)("hello");
2 - var person = { score: 25 };

  // With pipe:
  var newScore = person.score
    |> double
    |> score => add(7, score)
    |> validateScore

  // With compose and curry:
  var newScore = compose(validateScore, curry(add(7), double);
  newScore(person.score);
3 - Mixin paradigms

  // With compose and curry :
  var newScore = Function.compose(validateScore, add.curry(7), double);
  newScore(person.score);
(comment deleted)
(comment deleted)
(comment deleted)