[HN Gopher] A pipe operator for JavaScript: introduction and use...
       ___________________________________________________________________
        
       A pipe operator for JavaScript: introduction and use cases
        
       Author : kiyanwang
       Score  : 77 points
       Date   : 2022-01-29 08:28 UTC (14 hours ago)
        
 (HTM) web link (2ality.com)
 (TXT) w3m dump (2ality.com)
        
       | mfbx9da4 wrote:
       | I don't support the pipe operator. I want my code to look like it
       | came out of a beginners book. Esoteric syntax makes it hard for
       | somebody new to the language to understand your code. Codegolf is
       | cool but not helpful
        
         | uryga wrote:
         | "programming shouldn't evolve, it should look like what i
         | learned N years ago"? ;)
        
           | ricardobeat wrote:
           | That's a strawman. Is it "evolution" if it makes the language
           | harder to learn, with no practical benefits other than "it
           | looks cooler"?
        
             | sdeframond wrote:
             | I believe "harder to learn" is highly subjective in the
             | same way that Japanese is hard to learn for a native
             | English speaker but easy to learn for a Chinese.
             | 
             | Granted, Haskell and Scala are pretty "rich" and not
             | beginner-focused.
             | 
             | OTOH, a language like Elm has a pipe operator and manages
             | to keep things pretty simple.
             | 
             | Now does javascript need the _added_ complexity? Tough
             | call.
        
               | brigandish wrote:
               | > Japanese is hard to learn for a native English speaker
               | but easy to learn for a Chinese
               | 
               | This isn't to detract from your overall point but I study
               | Japanese and many of my fellow students are Chinese, they
               | certainly don't find it easy, even with the advantage of
               | being able to infer most kanji. Korean to Japanese might
               | fit the example better.
        
             | uryga wrote:
             | that's fair, i was in a spicy mood.
             | 
             | there's "esoteric" as in fundamentally complicated, and
             | """esoteric""" as in syntax that's unfamiliar but easily
             | explained w/ a quick web search.
             | 
             | i believe "it's nicer to express some things this way" is a
             | very important practical benefit. for me, "being expressive
             | for experienced users" is ultimately more important to
             | optimize for than """learnablility""", scare quotes
             | intended. because beginners will be beginners for a while,
             | and then they won't. (i dislike e.g. Go for this reason,
             | but let's not get sidetracked)
             | 
             | (before you or someone else asks: i've tutored many
             | beginner/first-time programmers, and yes, i still think a
             | bit of syntactic sugar won't hurt them)
        
             | kroltan wrote:
             | The practical benefit is that, unlike say Lodash's
             | chaining, it is outwardly extensible, you don't need to
             | write every function into a big object (and worry about
             | naming clashes).                 _.chain(inputSet)
             | .filter((x) => x >= 0)           .map((x) => x * 2)
             | .thru((e) => new Set(e))           .value()
             | 
             | Assumes chain returns a object with {filter, map, thru,
             | value}, and if you want a new operation you need to assign
             | it to that object, which means the library that returned
             | the original object must expose that too, and everyone
             | knows "Prototype Extension Is Bad" since you could come up
             | with a method name that someone else came up with too, then
             | you'd override things and introduce bugs.
             | 
             | With chaining (even ignoring the % Hack syntax for
             | placeholder expressions) you can use functions from
             | anywhere: local variables, other objects, anything you
             | want, even if the library that provided the original data
             | is not viable to modify, since it _doesn 't need to be
             | modified_.
             | 
             | Another way of approaching this extension problem is, well,
             | with extension members, like Kotlin or C#, where you can
             | declare free functions to operate on a "this" of a specific
             | type, and then you can use it exactly as if it was a method
             | of the type. Of course, JS is dynamically typed so that
             | wouldn't be viable in this case.
             | 
             | Finally, I think that for JS specifically, a pipe function
             | is enough. Sure you have a few more commas around but it's
             | fine. I could see the appeal of having an operator in
             | TypeScript, since it would mean that types would be
             | preserved much better.
        
               | ricardobeat wrote:
               | You can make a similar argument for JSX, private
               | properties, etc. The point is that there will always be
               | use cases that see massive improvements from a feature,
               | but that doesn't mean it's worth adding it to the
               | language and paying the price in specification and
               | implementation complexity, surface area and learning
               | curve. Especially if it doesn't enable any new use cases.
               | 
               | If the 5% of people that benefit can get 90% there using
               | userland libraries, the cost of that 10% improvement
               | should not be bore by the other 95%.
        
             | throwamon wrote:
             | > no practical benefits other than "it looks cooler"
             | 
             | That is a very ignorant take and only shows that you
             | haven't taken the time to learn the first thing about
             | functional programming.
        
         | BoiledCabbage wrote:
         | Good news, it will look like it came out of a beginners book,
         | as the pipe operator gets added to beginners books. Just like
         | arrow functions.
         | 
         | Your argument at this point is "I don't like it because it's
         | new."
         | 
         | You should possibly instead argue on the merits of what it is.
         | 
         | Simple syntax, and straightforward behavior.
        
           | lil_dispaches wrote:
           | Simple syntax, like how '=>' is a two-character ASCII art
           | 'fat arrow', and not anything to do with logical equivalence.
           | That's how you syntax for beginners!
        
         | dnautics wrote:
         | You have no idea how much it improves the readability and
         | understandability of code.
        
         | throwamon wrote:
         | Saying this about JavaScript of all languages... The pipe
         | operator is about the _least_ likely to be confusing to a
         | beginner.
         | 
         | And it's hardly "esoteric" when it's been around for decades in
         | well-established languages (including bash, for God's sake).
         | Just like the other commenter, you're only showing your
         | ignorance of other paradigms here. Just because you were
         | introduced to something else first, doesn't mean it's
         | automatically the most intuitive way for everyone forever.
        
           | irrational wrote:
           | I disagree. A true begineer is unlikely to be familiar with
           | bash or these other languages.
           | 
           | Syntax like + - / * () = etc. are not esoteric since, for the
           | most part, they work similar to math they learned in school.
           | 
           | But => and |? They are esoteric. As a beginner you have no
           | idea what they will do without study.
        
             | mcaruso wrote:
             | => also comes straight from math learned in school. There
             | it's written - (for function signatures), and (the more
             | rare) - for function definitions.
        
             | throwamon wrote:
             | > for the most part
             | 
             | That's the important bit. If they _always_ worked as
             | expected, I 'd agree. But they don't. I could give plenty
             | of examples but I'm sure you know about them.
             | 
             | > A true begineer is unlikely to be familiar with bash or
             | these other languages
             | 
             | I'm with you on Bash, but not necessarily about "these
             | other languages". Lots of people are being introduced to
             | functional languages first, and if you don't think so
             | you're probably just old.
             | 
             | I also don't assume a beginner will just be given code
             | without _any_ guidance. What do you think about dot
             | notation? If they can /can't understand
             | `foo().bar().baz()`, then surely they can/can't understand
             | `foo() |> bar() |> baz()` all the same?
             | 
             | Actually the "lack of familiarity" argument is the best
             | argument for introducing it in JavaScript: It's _the_
             | language beginners are learning nowadays, so if it has
             | feature x as a prominent feature, in a few years everyone
             | will know about it.
        
           | magicalist wrote:
           | > _including bash_
           | 
           | bash scripts famous for being readable and maintainable :P
        
             | throwamon wrote:
             | I fully agree with your sarcasm, but you probably know that
             | that was not my point.
             | 
             | But seriously, I don't see what's so controversial about
             | it. It's just "do this, then take the result and do that,
             | then take the result and..." Everyone understands this
             | intuitively. Plus, lots of libraries already do method
             | chaining, which is just a crappier and inconsistent version
             | of piping anyway.
        
         | sfvisser wrote:
         | I think this argument makes sense in _some_ usecases, but
         | definitely not everywhere.
         | 
         | There are genuine places where a FP approach to API/DSL design
         | makes sense and writing code that abstracts away from concrete
         | parameters and focuses on composition is important. Operators
         | for function application and composition can now be used for a
         | similar concepts on a higher level of abstraction.
         | 
         | Suddenly 'esoteric' syntax helps clarify your code and forces
         | you to focus on meaning and intent, not syntactic details of
         | your PL.
        
         | goto11 wrote:
         | I'm a firm believe in "keep it simple" and "don't be clever"
         | when it comes to code I have to maintain. But at the
         | programming language level I want powerful constructs. I want
         | to maintain simple and straightforward code in a powerful
         | language, not the other way around.
        
         | irrational wrote:
         | Unfortunately we already have arrow syntax, which is as
         | esoteric as it gets. I think the idea of arrow syntax is good,
         | but the chosen syntax sucks.
        
           | mickael-kerjean wrote:
           | js is already a mixed bag of stuff, at least the pipe is
           | usefull in making code cleaner especially compared to other
           | features like:
           | 
           | 1. support for class because you know real programmer don't
           | like prototypal inheritance and prefer to type the word class
           | in their code. In the meantime, let's make a compiler to
           | translate that code onto something an old engine will also
           | understand, yeah that sounds like an amazing idea and tada
           | babel is now the centerpiece of everything
           | 
           | 2. so many way to create a for loop, put a few footguns with
           | the for in syntax, mix it with a few functions in the array
           | proto cleverly named: forEach and map so now we need a linter
           | to enforce a style
           | 
           | 3. let's put some await async everywhere but forget about
           | cancellation because things can't go wrong anyway
           | 
           | 4. let's make different standard for packaging and import
           | with workaround everywhere so there's no code reuse in
           | between front and backend code even though the primary
           | arugment for nodeJS in the early day was code reuse
           | 
           | 5. let's not talk about code that rely on null == undefined
           | to be true and Number(null) to be 0 but Number(undefined) to
           | be NaN, ....
           | 
           | ...
        
         | adam12 wrote:
         | It's not esoteric if you are a functional programmer.
        
       | tzs wrote:
       | Here are the two forms being offered for a pipe operator:
       | const y = h(g(f(x))); // no pipe       const y = x |> f(%) |>
       | g(%) |> h(%); // Hack pipe       const y = x |> f |> g |> h; //
       | F# pipe
       | 
       | Why not use concatenation?                 const y = x f g h;
        
         | bryanrasmussen wrote:
         | In that case why not write
         | 
         | h g f x
         | 
         | and keep the ordering of functions the same between the
         | different syntactical structures.
        
         | angus_gh wrote:
         | Does your suggestion allow passing an extra argument into any
         | of those functions? Like the                   value |>
         | someFunction(1, %, 3)
        
         | johannes1234321 wrote:
         | > Why not use concatenation? > > const y = x f g h;
         | 
         | This can't be broken into multiple lines.
         | const y = x f        g h
         | 
         | Will have an implicit ; in between.                  const y =
         | x                |> f               |> g               |> h;
         | 
         | Will work as expected, and potentially increase readability.
        
         | zeroimpl wrote:
         | Because then a missing comma somewhere becomes a weird bug, as
         | opposed to a syntax error.
         | 
         | Languages with implicit string concatenation using no operator
         | have found it to be a common source of bugs, eg python. See
         | https://news.ycombinator.com/item?id=29841560
        
       | samatman wrote:
       | I guess it's my day to represent the Smug Lisp Weenie+ faction of
       | Hacker News?
       | 
       | + https://wiki.c2.com/?SmugLispWeenie
       | 
       |  _This is what happens when you don 't have user extensible
       | syntax_, you end up petitioning committees for... another way to
       | write a threading macro.
       | 
       | If you want macros so badly have you considered, wait for it,
       | s-expressions?
        
         | Zababa wrote:
         | > This is what happens when you don't have user extensible
         | syntax, you end up petitioning committees for... another way to
         | write a threading macro.
         | 
         | There is user extensible syntax, JS users have been using
         | macros for years through Babel. Here's the plugin for the
         | different pipes: https://babeljs.io/docs/en/babel-plugin-
         | proposal-pipeline-op...
        
         | ReleaseCandidat wrote:
         | > If you want macros so badly have you considered, wait for it,
         | s-expressions?
         | 
         | Actually the only acceptable way to define a 'pipe' (aka.
         | reverse function application) is something like
         | x YOUR_SYMBOL_OF_CHOICE f = f x
         | 
         | Every language that needs more than this is already seriously
         | flawed :D
        
           | samatman wrote:
           | Ok so I have one counteroffer:                  (-> _ f x)
           | 
           | Deal?
        
             | ReleaseCandidat wrote:
             | Ok, because it's weekend!
        
         | cageface wrote:
         | This is true. On the minus side writing tooling for an s-expr
         | language is much much harder. Being able to reliably refactor
         | my typescript code with a key press is a big plus.
        
           | samatman wrote:
           | It's not supposed to be!
           | 
           | https://shaunlebron.github.io/parinfer/
           | 
           | A better world is possible!
        
             | cageface wrote:
             | This looks nice but doesn't seem to come close to the kind
             | of structural understanding of code that you get with
             | statically typed languages with a fixed syntax.
        
       | ReleaseCandidat wrote:
       | Well, you can easily (and not that ugly) curry JS-functions by
       | using arrow notation:                  f(a)(b)(c) -> f = (a) =>
       | (b) => (c) => {...}
        
       | codethief wrote:
       | I was recently made aware of D's Uniform Function Call Syntax
       | (UFCS) which is similar but not exactly the same:
       | void sun(T, int);              void moon(T t)         {
       | t.sun(1);             // If `T` does not have member function
       | `sun`,             // `t.sun(1)` is interpreted as if it were
       | written `sun(t, 1)`         }
       | 
       | The nice thing here is that no placeholder like % is needed and
       | it still works with functions that expect multiple parameters.
       | 
       | Docs: https://dlang.org/spec/function.html#pseudo-member
        
         | jkcxn wrote:
         | D's way is far superior because as the caller you don't have to
         | worry about whether you're calling a method or an external
         | function, it looks the same. Not sure it would be possible to
         | tack this onto a dynamic language like JavaScript though
        
         | egeozcan wrote:
         | I think Nim has the same, IIRC.
        
           | davidkunz wrote:
           | That is correct, they call it "method call syntax":
           | https://nim-lang.org/docs/tut2.html#object-oriented-
           | programm...
        
         | dtech wrote:
         | Interesting, it's also general enough to cover extension
         | methods where languages C#, Kotlin and Scala have special
         | constructs for.
        
       | egeozcan wrote:
       | I've been experimenting with this via a babel plugin for a while.
       | 
       | The difference in ergonomics is huge, and it's readable too!
       | 
       | At first, I was so excited to try it, I wanted to "simulate it"
       | via some library I developed: https://github.com/egeozcan/ppipe
       | Then I realized it was super hard to add typings for it (I use
       | Typescript nearly exclusively these days).
       | 
       | Anyway, I can't wait this to be adopted by Typescript!
        
         | ricardobeat wrote:
         | This idea has been toyed with for a decade. Im pretty sure
         | lodash still has a pipe method somewhere. I actually prefer the
         | `.pipe` function over the proposed operator, but we've had that
         | available for 10+ years with very little adoption.
         | 
         | Unless the new operator was wildly easier to use (it's not),
         | that adoption says everything we need to know about the need to
         | add this feature to JS.
        
           | egeozcan wrote:
           | I did develop a library and am still of the opinion that the
           | native implementation is vastly superior.
           | 
           | You cannot use .pipe unless you break other code and start
           | changing prototypes of all the things, or you wrap the result
           | every time.
           | 
           | So when I'm writing an expression, I need to go back and
           | write pipe(expression).pipe(...
           | 
           | Also the placeholder is much easier to use than using
           | something like my solution (const _ = pipe._) for it. You
           | don't need to remember importing/defining it!
           | 
           | I was even toying with a crazier version (notice the extra p,
           | yeah I suck at naming things):
           | https://github.com/egeozcan/pppipe/
           | 
           | The only reason that exists is to prevent the clutter of
           | writing .pipe all the time.
           | 
           | Yet another reason is, you'd get autocomplete with a native
           | implementation, and also TS support!
           | 
           | Also, it's been toyed for surely more than a decade, even my
           | library is 6 years old (older if you count my previous non-
           | public attempts).
        
         | mirekrusin wrote:
         | You can type it, take a look at pipe and pipe1 in [0].
         | 
         | [0] https://github.com/preludejs/generator/tree/master/src
        
           | egeozcan wrote:
           | Mine is a bit more complicated, unfortunately (me from 6
           | years ago had so much ambition, and implemented all the
           | things)
           | 
           | Also this:
           | 
           | https://github.com/preludejs/generator/blob/master/src/pipe..
           | ..
           | 
           | Wait, what? :)) I'm not ready to deal with something like
           | that (just to make sure it doesn't come as arrogant, I mean I
           | just don't trust myself)
        
             | mirekrusin wrote:
             | Yes, pyramid of hell. I said it "can be typed", I didn't
             | say it's "pretty"! :)
        
       | dagurp wrote:
       | On using intermediate variables
       | 
       | > "On one hand, that's more verbose than piping. On the other
       | hand, the variable names describe what is going on - which can be
       | useful if a step is complicated."
       | 
       | If the only downside is that it's a little verbose then I still
       | don't see the benefit of having pipes.
        
         | [deleted]
        
       | metadat wrote:
       | Yuck, I wish they'd just stop messing with the JS language
       | primitives and syntax already and just let it be. Less is more.
       | 
       | What's that quote? Something along the lines of:
       | 
       | "Any idiot can make something more complex, it takes true genius
       | and courage to simplify."
       | 
       | Crawford's book:                   JavaScript: The Good Parts
       | 
       | Is a very thin book and pretty much sums it up for the actual
       | useful important bits I needed to know. Don't need to save a few
       | lines here and there with new unintuitive, esoteric operators.
       | 
       | Python also has the same disease as of late, with "features" like
       | the addition of the async keyword and introducing multiple ways
       | of accomplishing the same thing. It's sad to see previously
       | beautiful, elegant giants grow random trendy warts. They could
       | have remained opinionated, pragmatic, and timeless instead. Could
       | have left async to the mess that is Twisted (which was useful and
       | fine as it was!).
       | 
       | /rant, sorry.
        
         | threatofrain wrote:
         | I see Doug Crockford's book as a dark magic tome for the dark
         | ages of JS, but that time has passed. Even the codebase of
         | Crockford's old ESLint has moved on to modern JS.
         | 
         | That book was published right around the release of Node.JS,
         | the iPhone 3GS, and very shortly after came NPM. So the JS
         | community did not have proper modules back then and would use
         | immediately invoked anonymous functions to mutate the global
         | scope to create a sense of namespace modularization.
         | 
         | The retrospective consequence is that valid JS namespaces like
         | _ and $ are no-go zones for the community, and possibly forever
         | so. Modifying the prototype of common objects also did not help
         | (flat vs flatten). Not a harmonious way of relating to the
         | neighborhood IMO.
         | 
         | And on the matter of async, what we used to have was a hack
         | given by the popularization of a Microsoft browser API.
        
       | ricardobeat wrote:
       | We have WASM now. At this point people could just make their
       | dream version of Javascript, with pipes, private class members,
       | abstract factories and the like, and leave JS alone, it's been
       | damaged way too much already.
       | 
       | </rant>
        
         | egeozcan wrote:
         | > it's been damaged way too much already
         | 
         | Why? It's one of the most comfortable languages for me.
         | 
         | Some parts of it are objectively bad, sure, but why even touch
         | those parts when the language constantly gets updated and
         | modernized... I'm saying this as a developer who mainly writes
         | C# and Go these days.
         | 
         | With JS, without dabbling in wasm wizardry, I can open a
         | console in the browser and directly get an environment with
         | crazy interaction possibilities.
         | 
         | If I'm writing something for the long run, I can use a lighter
         | compile-to-JS language like Typescript (my fav) and when
         | there's an error, I can directly map what's going on to actual
         | source code without even using source-maps. In addition to
         | that, admittedly like many other languages, I can write 2 lines
         | of it in a file, double click the file, and have a web server
         | running! It's amazing that JS gets more and more love, and
         | there are many of us caring for it.
         | 
         | The whole rhetoric that "JS is bad" is getting old. People talk
         | down JS then start using others where white space count
         | matters... Yeah it's all preference but that is my point as
         | well. If you don't like JS direction, you can use your favorite
         | lang via WASM, and let JS get developed in a faster pace as
         | well.
         | 
         | So TL;DR: Why not think the other way around the issue!
        
       | karmakaze wrote:
       | I would go for a split of the currying and proposed solutions.
       | Logically                 y = x |> f2(a, _)       y = x |> f2(_,
       | b)
       | 
       | are currying, but the implementation doesn't need to create
       | functions any more than if the _ was %. And                 fb =
       | f2(a, _)       fa = f2(_, b)
       | 
       | are explicit currying which would be nice to have at times, but
       | would mostly use in piped context at first, perhaps to give it a
       | more meaningful or narrowed-scope name.
        
       | TrianguloY wrote:
       | Also reminds me of Kotlin 'let':                   val y =
       | h(g(f(x)))
       | 
       | is the same as                   val y = x             .let{
       | f(it) }             .let{ g(it) }             .let{ h(it) }
       | 
       | I have used and loved the pipe operator in Elixir, but always
       | missed using it for functions where the data is the second
       | argument, for example. It's slightly less verbose, but more
       | restricted and more complex to understand. I prefer the
       | JavaScript approach.
       | 
       | In any case, I find it odd using the % as the variable name.
       | Maybe if the operator was x %> f(%), but that probably is an
       | invalid token.
        
       | arh68 wrote:
       | The lodash equivalent, which I missed, is something like this:
       | _.chain(inputSet)           .filter((x) => x >= 0)
       | .map((x) => x * 2)           .thru((e) => new Set(e))
       | .value()
       | 
       | I think it looks fine, works fine.
        
         | rco8786 wrote:
         | To be clear, this is plain javascript. The only lodash does
         | here is the initial _. And you're right, it does work just
         | fine.
        
           | webstrand wrote:
           | That's not plain Javascript. That's Lodash through and
           | through. The array transformation methods built into
           | Javascript run to completion after every step building
           | multiple copies of the array as each transformation is
           | applied. Lodash's chain and related methods do not make
           | multiple copies of the array during transformation.
        
             | bunnyfoofoo wrote:
             | Hey, do you have more documentation on how vanilla
             | Javascript handles array transformations? As an example:
             | array.filter(f => true).map(f => f);
             | 
             | My understanding is that filter creates a new array, then
             | maps that new array to another new array in final step.
             | 
             | Does lodash do something differently? I'm not seeing
             | anything in documentation for _.chain that says it does
             | something differently.
        
             | e12e wrote:
             | How so? Looks like filter builds a new array, and so does
             | map? And both _while_ -loops over the entire input?
             | 
             | https://github.com/lodash/lodash/blob/master/filter.js
             | 
             | https://github.com/lodash/lodash/blob/master/map.js
             | 
             | With a quick search I found this:
             | 
             | https://hackernoon.com/es6-lodash-native-javascript-
             | nodejs-e...
             | 
             | Which seems to indicate little difference?
        
         | n_e wrote:
         | > I think it looks fine
         | 
         | _.chain and .value() could be removed
         | 
         | > works fine.
         | 
         | - it isn't possible to tree-shake the package and only include
         | the lodash functions that are used - it isn't possible to have
         | non-lodash functions in the pipeline (e.g. date-fns)
        
       | valenterry wrote:
       | > For await and yield, we'd need special syntax - e.g.: > value
       | |> await // awaiting a Promise
       | 
       | As much as await is nice and helps code to look cleaner - it
       | should be noted that this example is one of the reasons why
       | language designers have to be careful when adding syntax to
       | support "special cases".
       | 
       | It makes every change down the road just a little bit harder /
       | more complicated.
        
       | lambdaba wrote:
       | LiveScript (https://livescript.net/) has this, amongst many other
       | things (mostly CoffeeScript-inspired). I used it quite a bit and
       | enjoyed it a lot.
        
         | k__ wrote:
         | Yes, LiveScript was like CoffeeScript in good.
         | 
         | I really liked that it was so concise.
         | 
         | But somehow static typing was deemed more important an, so it
         | never gained traction.
        
       | AlbertoGP wrote:
       | > _The proposal "Pipe operator (| >) for JavaScript" [...]
       | introduces a new operator [...] borrowed from functional
       | programming that makes applying functions more convenient in many
       | cases._
       | 
       | I put a brief comparison of the syntax for Shell `|`, Haskell
       | `&`, Elixir `|>` and Clojure `->` in the documentation for my
       | version for C `@`: https://sentido-
       | labs.com/en/library/cedro/202106171400/#back...
       | 
       | There, each operator is a link to the corresponding documentation
       | page if you'd like to know more.
        
       | rco8786 wrote:
       | Not really in support for many reasons - but did nobody think
       | about the difficulty of this syntax for even 2 seconds?
       | 
       | A shift + pinky reach for the | followed immediately by a shift +
       | ring finger curl on the same hand? And tbh is is something
       | developers are supposed to use frequently? No thanks.
        
         | davydog187 wrote:
         | I do this every day in Elixir and it's never been a problem.
         | You get used to it
        
         | ReleaseCandidat wrote:
         | You do know that there are different keyboard layouts? `|>` is
         | <AltGr> + <w> + <y> (no reason to lift the right thumb from
         | <AltGr>) for me
        
           | pie_flavor wrote:
           | Not-inconvenient for some doesn't change inconvenient for
           | most. Most keyboard layouts are based on the US's. I have the
           | same complaint about -> as a method locator like PHP does.
        
             | loopback_device wrote:
             | Most keyboard layouts do not have symbols anywhere near the
             | places they are on the US layout. Letters, yes, but not
             | brackets, punctuation etc.
        
       | reverseblade2 wrote:
       | You can instead just use F# today for Javascript via fable.io
        
         | ReleaseCandidat wrote:
         | Or PureScript with `#` (or any other symbol that pleases you,
         | it's just a trivial definition away ;), or ReScript with `->`
        
       | bryanrasmussen wrote:
       | I like languages with a small instruction set, which is what
       | JavaScript definitely was some years ago, I would say not so much
       | any more.
       | 
       | Even worse it has bits of functionality that are now layered on
       | top of each other - so hoisting still happens unless you use
       | const and let, there is strict mode which exists if you put the
       | use strict declaration or have things in a module, but otherwise
       | you might make a mistake somewhere and have things polluting the
       | global scope that either you thought was impossible or even worse
       | you were not aware that was even a possibility with the language
       | because you were raised in a garden where it was not allowed,
       | only now a bug brought a bit of the wilderness in to you and you
       | don't understand what the heck is going on.
       | 
       | So to escape these problems with the language use linters, but
       | some times people turn off linters etc. etc.
       | 
       | The suggestion to deal with problems of the language seem always
       | to be:
       | 
       | 1. Add more syntax, meaning more special cases to remember how
       | things behave with that syntax!
       | 
       | 2. Be disciplined and good and you will never experience these
       | problems that the language has. Also all of your team needs to be
       | disciplined and good, and the people who used to be on the team
       | before you joined should be disciplined and good, and thus there
       | should not be any code that is old enough to be written in a way
       | that does not fit our modern definitions of disciplined and good.
        
         | mirekrusin wrote:
         | You could have programming language with just NAND as "small
         | instruction set".
         | 
         | The reality is that you want "instruction set" that you're
         | using to solve your problems. But other people will want to
         | work on different abstraction levels - yours and theirs desired
         | "instruction set" will vary.
        
           | bryanrasmussen wrote:
           | >The reality is that you want "instruction set" that you're
           | using to solve your problems.
           | 
           | yeah either that or by having a small instruction set you can
           | know all the language at a reasonably deep level, but with a
           | large enough language and the need to write maintainable code
           | this becomes more difficult. You may be hit with situations
           | where you need to look up the specification of the language
           | you are supposed to be an expert in.
           | 
           | But you're right, you definitely know better than I what I
           | mean when I say I like languages with a small instruction
           | set.
        
             | mirekrusin wrote:
             | It helps to have terse code constructs (destructuring) or
             | more sane behaviour (const/let vs var scoping). I don't
             | think constructs like pipe operator, nullish coalescing or
             | optional chaining hampers language to the point that it
             | becomes impossible to know at reasonably deep level. Those
             | are quite fundamental, often quite simple, concepts and
             | many of them are sprinkled around different languages here
             | and there already. TypeScript for example has much harder
             | learning curve. Personally I find things like generators,
             | async generators, tagged templates absolutely essential in
             | day-to-day work and can't imagine working without them.
             | Recent additions to JavaScript language through healthy
             | community interaction were absolutely great IMHO.
        
       | dang wrote:
       | Past related threads:
       | 
       |  _A Pipe Operator for JavaScript_ -
       | https://news.ycombinator.com/item?id=30107263 - Jan 2022 (1
       | comment)
       | 
       |  _A pipe operator for JavaScript: introduction and use cases_ -
       | https://news.ycombinator.com/item?id=30097586 - Jan 2022 (1
       | comment)
       | 
       |  _A proposal for adding a pipe operator to JavaScript_ -
       | https://news.ycombinator.com/item?id=28916775 - Oct 2021 (180
       | comments)
        
       | [deleted]
        
       | CSSer wrote:
       | > const y = h(g(f(x))); This notation usually does not reflect
       | how we think about the computational steps.
       | 
       | Do others feel this way too? I have to admit I don't really see
       | it. It seems like a very subjective syntactic decision to me. Why
       | not assign each call to a variable for readability? GC overhead?
       | I guess naming things is hard, so sometimes you're just going to
       | do things like:
       | 
       | halve(double(triple(5)))
       | 
       | But honestly this doesn't seem that hard to read to me for
       | reasons that are perhaps beyond me. Granted, JS is my mother
       | tongue, so maybe I'm just brainwashed.
       | 
       | I think I'm also hung up on the use of % because it already has
       | the job of being the remainder operator. Are there other examples
       | in the language where operator behavior changes in different
       | contexts that are similar to this I'm missing (aside from the
       | obvious order of operations or operator associativity)?
        
         | oweiler wrote:
         | People read left to right, not inside out. Local vars can make
         | reasoning harder, because they are visible throughout the
         | current scope.
        
           | tgv wrote:
           | Only "half" the world reads LTR.
        
             | learc83 wrote:
             | Everyone who uses JavaScript reads most of JavaScript left
             | to right.
        
         | arnvald wrote:
         | > Why not assign each call to a variable for readability?
         | 
         | The problem is that if you use a variable, you either:
         | 
         | - use a new variable each time, therefore you have to think of
         | appropriate name each time (and having a lot of variables does
         | not necessarily make code more readable)
         | 
         | - or you have to come up with a rather generic name of
         | variable, like "result" or "output", otherwise the name will
         | not make sense until the very end where the last value is
         | assigned
         | 
         | Let's say I want to have a list of active products from some
         | category. With option 1 it would be:                 const
         | allProducts = Product.all()       const activeProducts =
         | allProducts.filterActive()       const activeHouseProducts =
         | Category.match(activeProducts, "house")
         | 
         | with option 2 you'd do:                 var activeHouseProducts
         | = Product.all()       activeHouseProducts =
         | activeHouseProducts.filterActive()       activeHouseProducts=
         | Category.match(activeHouseProducts, "house")
         | 
         | and with pipe operator you can do:                 const
         | activeHouseProducts =         Product.all().filterActive() |>
         | Category.match(%, "house")
        
           | magicalist wrote:
           | FWIW it seems like option 1 should actually be
           | const activeProducts =         Product.all().filterActive()
           | const activeHouseProducts = Category.match(activeProducts,
           | "house")
        
         | TedDoesntTalk wrote:
         | > are there other examples in the language where operator
         | behavior changes in different contexts
         | 
         | The newish Elvis operator
        
         | nkozyra wrote:
         | The use of the term "pipe" definitely implies a sequential
         | pipeline, and in that sense I agree with the author.
         | 
         | But it really only manifests after a few function calls, at
         | which point you're forced to find the initial value and
         | recursively parse the methods. The example is probably
         | unrealistic and not real world, but it's a speed bump I've
         | encountered in real code.
         | 
         | Per your example - which is definitely less abstract - it would
         | still feel more intuitive to see
         | 
         | 5 | triple() | double() | halve ()
         | 
         | My issue is the syntax in the proposal, which may feel like
         | another language's implementation, but doesn't really feel like
         | JavaScript. Mentally thinking about JS as an "everything is an
         | object" paradigm, just having a breakout-and-apply chain that
         | looked closer to a dot operator would be more native feeling.
         | 
         | ('25').|parseInt(%).|math.Sqrt(%)
         | 
         | Other languages imply the pipe "direction" pass-off with syntax
         | like -> but JS has traditionally eschewed that with more apply-
         | transformation-in-place syntax.
        
       | jeroenhd wrote:
       | I get why a lot of people here dislike the pipe operator, but I
       | actually love it. The application I work on has tons of obscure
       | javascript processing in the frontend and I can already think of
       | several places where would make the code look much cleaner.
       | 
       | Sadly, it's also stuck in the past so if and when this operator
       | gets accepted into Javascript, it'll take years before the
       | necessary code cleanup can happen.
        
       | beebeepka wrote:
       | Decisions, decisions.
       | 
       | On one hand, having a pipe is real nice. Some flows are better
       | represented like thwt. On the other, this example doesn't make
       | sense to me.
       | 
       | const y = h(g(f(x)));
       | 
       | const y = x |> f(%) |> g(%) |> h(%)
       | 
       | How is the hack pipe easier on the eyes and mind? Also went
       | through the rest of the article and I have to say things don't
       | get better in terms of readability.
       | 
       | That said, it's arbitrary. I have no doubt many would disagree
       | with me given how often I see people writing code as if it's
       | unthinkable to have more than a handful of symbols on a row.
        
         | ReleaseCandidat wrote:
         | const y = h(g(f(x)))         const y = x |> f(%) |> g(%) |>
         | h(%)
         | 
         | It get's better with                  const y =           g * k
         | + j / w * d - 453368423            |> (x) => { 4566 * x + 46832
         | - x * x + 1 / x}(%)            |> (x) => { x / 4653 + 843 * x
         | *x }(%)             |> (x) => { 486543 - x + x * x }(%)
         | 
         | The question is if you often do things like that, though ;)
        
           | nmcfarl wrote:
           | The example that resonates with me is when the functions have
           | multiple parameters:                   const y = h(1,
           | g(f("world", x, 3 ),true))         const y = x |> f("world",
           | x, 3) |> g(%, true) |> h(1, %)
        
           | jlokier wrote:
           | More readable, imho:                 const a = g * k + j / w
           | * d - 453368423       const b = 4566 * a + 46832 - a * a + 1
           | / a       const c = b / 4653 + 843 * b * b       const y =
           | 486543 - c + c * c
        
             | ReleaseCandidat wrote:
             | I actually do prefer this too.
             | 
             | And when using it for arrays, I'd prefer
             | const r = [a, b, c]                   .map((e) => 2 * e*e)
             | .filter((e) => e >= 0)                   .reduce((acc, e)
             | => acc + e)
             | 
             | to the new piped version.
        
       | djedr wrote:
       | This operator proposal has been there for quite some time! Seems
       | like it gets rediscovered periodically and continues to provoke
       | heated discussions.
       | 
       | Personally, I used to be fairly strongly against it, but nowadays
       | I'm not sure if I care. I suppose I'm still not particularly in
       | favor. But maybe I'm biased towards minimalism. I don't dislike
       | the idea of the operator in itself, just how it fits (or rather
       | doesn't fit) into JavaScript. I think it makes more sense in F#.
       | 
       | Four years ago I got really sucked into this topic and thought
       | about this a lot. I had a lot of fun writing down a few
       | counterarguments:
       | 
       | https://djedr.github.io/posts/random-2018-01-25.html
       | 
       | This was partly inspired by this HN thread:
       | 
       | https://news.ycombinator.com/item?id=16193112
       | 
       | It seems that since that time `Function.pipe` appeared as a
       | serious alternative or complement to the operator. Nice!
       | 
       | Besides `Function.pipe` these alternatives mentioned in the
       | article are good:
       | 
       | https://2ality.com/2022/01/pipe-operator.html#using-intermed...
       | 
       | https://2ality.com/2022/01/pipe-operator.html#reusing-a-vari...
       | 
       | The first one is actually the most simple, readable, safe, and
       | has been supported forever. It's just verbose and suffers from
       | the hard problem of naming things. Though sometimes just thinking
       | about a good name for an intermediate variable can lead to good
       | refactoring idea. And intermediate variables provide clean
       | breakpoints -- easier for debugging.
       | 
       | The next alternative solves the naming and verbosity problem.
       | Back when I was into this, I was writing a blog post about this
       | technique. Ended up not finishing it before my interest in
       | bikeshedding faded. Which reminds me to cut this post short and
       | tend to more pressing matters.
       | 
       | It can be fun though.
        
       ___________________________________________________________________
       (page generated 2022-01-29 23:02 UTC)