DEV Community

Cover image for Piping JavaScript
K
K

Posted on

Piping JavaScript

Cover image by arbyreed on Flickr.

JavaScript is getting more and more functional programming features, an exiting one is the new pipeline operator.

The operator is stage-1 so it won't be included in the standard right away, but you can already use it with the help of babel.

Why

If you come from an object oriented background, you probably used the dot operator quite alot. Many libraries use it to implement small DSLs, often called fluent interfaces, that help you to get things done with good readability.

For example Moment.js

moment().add(2, "days").substract(10, "hours").toString();
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

An functional alternative is date-fns/fp, but as you can see, the nested function calls make it a bit hard to read.

format("D MMMM YYYY", subHours(10, addDays(2, new Date())));
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Now wouldn't it be nice, to have this kind of left-to-right readability for functional code too?

What

This is where the new piping operator comes in handy, it allows you to make this kind of code more readable.

f(10);
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

becomes

10 |> f;
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

So the date-fns/fp example from above becomes

const add2Days = addDays(2);
const sub10Hours = subHours(10);
const customFormat = format("D MMMM YYYY");

new Date() |> add2Days |> sub10Hours |> customFormat;
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

or in short:

new Date()
|> addDays(2)
|> subHours(10)
|> format("D MMMM YYYY");
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

As you can see, the operator requires a function that only needs one argument. The date-fns/fp functions return such functions, when only called with one argument.

This also works with asynchronous functions, because they are build on top of promises, which return one result.

"USERID_123"
|> await loadUserFromApi // async
|> extractUserImageUrl   // sync
|> await cropUserImage;  // async
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ” ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”

Conclusion

Again, JavaScript takes a step into the FP direction and build on top of the additions it already had. Especially server-side data-transformation code will profit from code written this way.

Top comments (15)

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
brzdev profile image
𝔞𝔞ð”Ŋ𝔎ð”Ŧ ðŸ…Ĩ •

As an avid Elixir user this couldn’t make me happier!

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
codebryo profile image
Roman Kuba •

As I didn't come around to try this yet, I have one question.
Does the pipe operator know where to put the output of the previous function as input on the next one?
I am asking because:

const add2Days = addDays(2);

Takes the value as the second param.

const customFormat = format("D MMMM YYYY");

though takes the value as the first param.

Overall I think it's awesome that this comes to JS.
And a thank you for the posts you are putting out. Always looking forward to them.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
kayis profile image
K • • Edited

I think I wrote it wrong. It always uses the first argument. fixed it.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
alexcasalboni profile image
Alex Casalboni •

Coming from the "old world", it looks a bit weird at first :)

Looking at |> addDays(2), I would expect addDays(2) to be evaluated before being used as a function. In my mind, this can only work if addDays(2) actually returns a function.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
kayis profile image
K • • Edited

> In my mind, this can only work if addDays(2) actually returns a function.

This is what it does :)

A regular version of that function would look like that:

function addDays(amount, date) {...}

addDays(2, date);

A curried version looks like that:

const addDays = amount => date => {...};

addDays(2)(date);
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
functionalstoic profile image
JasonSooter • • Edited

I enjoy the pipe function in RamdaJS. It's gonna be nice to have this natively.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
skyrpex profile image
Cristian PallarÃĐs •

I guess it's the same as the flow function in Lodash, isn't it? I always use it!

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
kayis profile image
K •

RamdaJS is pretty awesome, yes.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
vekzdran profile image
Vedran Mandić •

I love it, and truly believe this is one small (big) step to popularize FP. Can be retrofitted with a pipe() fn (hint RamdaJS) for those who dislike the operator (for now!). Cool summary.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
Sloan, the sloth mascot
Comment deleted
ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
functionalstoic profile image
JasonSooter •

Why? It's a common and very much enjoyed operator in multiple other FP languages.

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
guid75 profile image
Guid75 •

Do you really prefer function1(function2(function3(function4(param))))?

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
kayis profile image
K •

Could you elaborate?

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
rapasoft profile image
Pavol Rajzak •

So, is this only syntactic sugar? I personally don't see any increase in readability when I compare |> something() to .something().

ðŸ”ī Hot News: kayis/piping javascript fdn - āļŠāļĢāļļāļ›āļ”āļĢāļēāļĄāđˆāļēāļĨāđˆāļēāļŠāļļāļ”
 
kayis profile image
K • • Edited

Yes.

You could see it as the FP equivalent to the dot operator of OOP.

v |> f to o.m()