[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)