Many languages have an operator that allows you to pipe the results of one operation into a call to another (e.g. the |
operator in bash, the |>
operator in F#).
One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:
var fooOddSquares = [1, 2, 3, 4, 5]
.filter(x => x % 2)
.map(x => "foo" + x * x)
.reduce(((acc, str, i) => acc[i + 1] = str; return acc), {});
// => {1: "foo1", 2: "foo9", 3: "foo25"}
compared to compositional code:
var something = func5(
func4(
func3(
func2(
func1(
somedata
)
)
)
)
);
which reads right-to-left, bottom-to-top. I realize this could be cleaned up via function composition, but that's not necessarily the point. Just to be absolutely clear with what I'm looking for:
var something = func1(somedata)
|> func2
|> func3
|> func4
//etc...
Doing a google search on the pipe operator in javascript mostly turns up info about the bitwise OR operation. With some digging however I was able to dig up this article describing a dirty-hacked version of operator overloading that could implement something of what I'm talking about. I also unearthed this gist that describes said operator and says that "it has been proposed for javascript".
Looking at ES 2016, I see proposals for an exponentiation operator and the bind operator. Both are useful, but not what I want. So per the headline in the gist, has anyone actually proposed this for javascript?
Many languages have an operator that allows you to pipe the results of one operation into a call to another (e.g. the |
operator in bash, the |>
operator in F#).
One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:
var fooOddSquares = [1, 2, 3, 4, 5]
.filter(x => x % 2)
.map(x => "foo" + x * x)
.reduce(((acc, str, i) => acc[i + 1] = str; return acc), {});
// => {1: "foo1", 2: "foo9", 3: "foo25"}
compared to compositional code:
var something = func5(
func4(
func3(
func2(
func1(
somedata
)
)
)
)
);
which reads right-to-left, bottom-to-top. I realize this could be cleaned up via function composition, but that's not necessarily the point. Just to be absolutely clear with what I'm looking for:
var something = func1(somedata)
|> func2
|> func3
|> func4
//etc...
Doing a google search on the pipe operator in javascript mostly turns up info about the bitwise OR operation. With some digging however I was able to dig up this article describing a dirty-hacked version of operator overloading that could implement something of what I'm talking about. I also unearthed this gist that describes said operator and says that "it has been proposed for javascript".
Looking at ES 2016, I see proposals for an exponentiation operator and the bind operator. Both are useful, but not what I want. So per the headline in the gist, has anyone actually proposed this for javascript?
Share Improve this question asked Nov 5, 2015 at 16:54 Jared SmithJared Smith 21.9k5 gold badges49 silver badges92 bronze badges 7 | Show 2 more comments4 Answers
Reset to default 15A pipeline operator has been proposed for ES7 (ES2016) in December 2015.
https://github.com/mindeavor/es-pipeline-operator
As mentioned already a pipeline operator has been proposed for ES7 (2016), however that doesn't help much if you want to use something like this right now with babel which exactly how I came across this question 9 months later.
The biggest hitch in supporting the es-pipeline-operator proposal through babel as far as I know is the current inability to use |>
or <|
as operators which create syntax errors and cannot be fixed without changes to babel and unfortunately does not look like the problem will be resolved any time soon.
I would personally like to see the pipe backward operator added to the proposal as well since both forward and backward are useful in different situations.
For example, I use the pipe backward operator when modifying functions or anywhere I would typically use "compose" over "pipe" which I prefer in certain situations for readability.
const something = curry <| function(state, pattern) {
// something
}
const something = function(state, pattern) {
// something
} |> curry
Because these pipe operators are incredibly useful in functional style javascript programming and for the benefit of anyone who came looking for a solution to use this right now like me, I have made a babel plugin that uses the bitwise operators <<
and >>
which I rarely use to achieve both forward and backward piping for the time being and in the rare cases where the bitwise operators are required the use of the "no pipe";
directive will disable the plugin for a certain scope.
https://github.com/michaelmitchell/babel-plugin-pipe-composition
This github repo and my favorite issue within it ;) discuss just that.
The proposal has been moving around in a small neighborhood of ideas for some months, but centers around using ->
and ::
as sugar around Function.prototype.apply
and Function.prototype.bind
, very roughly.
The current draft is for ::
to sit between a scope and function (instance::method
) and act much like instance.method.bind(instance)
, locking the this
scope of the function for any calls. Alongside that, ->
may be defined to pass a scope and array of arguments (as apply
), so instance->method(foo, bar)
would desugar to instance.method.apply(instance, [foo, bar])
. At least, that's one of the directions that is being discussed (disclosure: that's my take on it).
I usually just go like this:
var something = [somedata].map(func1).map(func2).map(func3).map(func4)[0];
It solves one of the main points in the question
One of the great advantages to my mind of the common idiom of method chaining in javascript is that it reads top-to-bottom, left-to-right:` by taking advantage of how this already exists for arrays.
because this feature already exists for arrays, and converting something into an array, and back again is easy enough.
the above uses the names in the question, but here is a concrete example:
console.log([9.3].map(Math.floor).map(Math.sqrt)[0]);
// or even this:
[9.3].map(Math.floor).map(Math.sqrt).forEach(x => console.log(x));
Promise.then()
? – Kijewski Commented Nov 5, 2015 at 16:56|>
operator seems to be implemented using a sweet.js macro – Bergi Commented Nov 5, 2015 at 17:04