News for hackers. Stuff that matters.
Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @10:49AM (#34454669)
Is this:

   Object.keys(envars)
     .map(envar => `${envar}=${envars[envar]}`)
     .join(' ')
     |> `$ ${%}`
     |> chalk.dim(%, 'node', args.join(' '))
     |> console.log(%);
Really better than:

  console.log(chalk.dim(
      `$ ${Object.keys(envars)
        .map(envar => `${envar}=${envars[envar]}`)
        .join(' ')
      }`,
      'node',
      args.join(' ')
  ));
That's the real-world example they have (I reformatted the second one slightly, because it looks better to me). Neither seems very good to me, and the |> version doesn't really seem "less bad".

Can also write it as:

   process.stdout.write(chalk.dim(
     `$ ${Object.keys(envars)
       .map(e => `${envar}=${e[envar]}`)
       .join(' ')
     }`,
   ))
   console.log(chalk.dim('node', args.join(' ')))
Which seems clearer than either because it splits out "print env variables" and "print out node args". And it would be even better with some sort of helper to convert an object to k=v string:

   console.log(chalk.dim(`$ ${dumpObj(envars)}`, 'node', args.join(' ')))
---

I also feel this:

> In the State of JS 2020 survey, the fourth top answer to “What do you feel is currently missing from JavaScript?” was a pipe operator.

Is the wrong way to go about language design. Everyone wants something different, and if you just implement the "top 5 most requested features" you're going to end up with some frankenbeast of a language.

Re:Pipe Operator (|>) For JavaScript by hajile on Friday January 20, 2023 @11:35AM (#34455548)
The F# syntax looks/acts a lot better here (especially paired with lodash). I also feel your code example wasn't done in the way people would actually use pipes.

    import {map, join} from 'lodash/fp' //iterators have better performance

    envars
    |> Object.entries
    |> map(([key, val]) => `${key}=${val}`)
    |> join(' ')
    |> x => chalk.dim('$ ' + x, 'node', join(' ', args))
    |> console.log
Even without lodash, it's still easy to read.

    envars
    |> Object.entries
    |> x => x.map(([key, val]) => `${key}=${val}`)
    |> x => x.join(' ')
    |> x => chalk.dim('$ ' + x, 'node', join(' ', args))
    |> console.log
For sake of completeness, here's the hack-based variant

    envars
    |> Object.entries(%)
    |> %.map(([key, val]) => `${key}=${val}`)
    |> %.join(' ')
    |> chalk.dim('$ ' + %, 'node', join(' ', args))
    |> console.log(%)
Re:Pipe Operator (|>) For JavaScript by captainmuon on Friday January 20, 2023 @11:42AM (#34455683)
The F# syntax would endlessly confuse me though. I'd always wonder whether |> join(' ') means join(x, ' ') or join(' ', x).
Re:Pipe Operator (|>) For JavaScript by hannasanarion on Friday January 20, 2023 @11:50AM (#34455849)
in F# syntax the right side is always a unary expression, so `|> join(' ')` means `|> join(' ')(x)`

(the requirement being that join(' ') returns a function that takes one arg)

Re:Pipe Operator (|>) For JavaScript by hajile on Friday January 20, 2023 @11:55AM (#34455951)
The top example relies on Lodash/fp having curried functions you can use.

The middle example would be using native stuff which is why you have the wrapper function (kinda like you'd have a function wrapping a callback)

Re:Pipe Operator (|>) For JavaScript by de_keyboard on Friday January 20, 2023 @02:10PM (#34458157)
The F# syntax is an incredibly simple bit of syntactic sugar.

Just replace this:

    x |> f
With this:

    f(x)

For the join example, you must do this:

    xs
    |> x => x.join(' ')
It de-sugars to:

    (x => x.join(' '))(xs)
... which of course is simply:

    xs.join(' ')
Re:Pipe Operator (|>) For JavaScript by captainmuon on Friday January 20, 2023 @08:49PM (#34462934)
Sure, I know. What I actually mean is that I don't grok curried functions.

Does join(a)(b) mean join(a, b) or join(b, a)? Does it mean a.join(b) or b.join(a)? And is a or b the delimiter? I don't really feel confident without looking it up or trying it out. I have a similar problem with Haskell's function syntax a -> a -> a.

If the function was called makeJoinerBy(sep)(array), it would be somewhat clearer:

    join = makeJoinerBy(' ')
    result = join(array)
Re:Pipe Operator (|>) For JavaScript by epolanski on Friday January 20, 2023 @02:39PM (#34458606)
Your example wouldn't work as the function would need to be unary.
Re:Pipe Operator (|>) For JavaScript by coffeebeqn on Friday January 20, 2023 @05:39PM (#34461103)
I mean it’s still not very readable. Reading through the code I can tell that it does.. some strong things with envars.
Re:Pipe Operator (|>) For JavaScript by trekkie1024 on Friday January 20, 2023 @06:01PM (#34461364)
Having done some personal projects in F#, I'm a huge fan of the syntax. However we would need most standard functions in JS to be curried to take advantage of it.
Re:Pipe Operator (|>) For JavaScript by wruza on Friday January 20, 2023 @06:22PM (#34461579)
it's still easy to read

That’s highly subjective I’m afraid.

“Take entries of envvars, turn that into k=v, join that by a space, make dim $, previous that, and args, log that”.

Personally I have no clue what’s going on at first glance with all these %%% “thats”. It’s meant to be declarative, but reads imperatively instead.

  console.log(chalk.dim(
    '$',
    ...Object.keys(envars)
      .map(k => `${k}=${envars[k]}`),
    'node',
    ...args,
  ))
“Log dimmed $, k=v pairs of envvars, node, then args”.
Re:Pipe Operator (|>) For JavaScript by hajile on Friday January 20, 2023 @08:33PM (#34462823)
That's why I prefer the F# version where it's just the names of functions or anonymous arrow functions. Nothing magical about them. It just calls the functions in order from top to bottom.
Re:Pipe Operator (|>) For JavaScript by dns_snek on Friday January 20, 2023 @11:24AM (#34455349)
I won't speak about the specifics of the chosen syntax (Hack/F#) but in general - absolutely.

With pipes you can visually follow the manipulations and function calls in the order that they happen instead of being forced to scan the code inside-out & outside-in, matching parentheses and function call parameters in your head, while still visualizing intermediate results to get 1 final return value.

I find Elixir code much easier and quicker to understand, in large part thanks to its (admittedly, imperfect) pipe syntax. Code written in this way is also much easier to debug because you can quickly add `console.log`, breakpoints, or equivalent between the pipes.

I find this unnecessarily time-consuming and difficult to parse and I'd likely raise some flags in a code review:

  console.log(chalk.dim(
      `$ ${Object.keys(envars)
        .map(envar => `${envar}=${envars[envar]}`)
        .join(' ')
      }`,
      'node',
      args.join(' ')
  ));

Without pipe syntax, I'd refactor this to:

  const envStr = Object.keys(envars)
        .map(envar => `${envar}=${envars[envar]}`)
        .join(' ');
  const styled = chalk.dim(`$ ${envStr}`, 'node', args.join(' '));
  console.log(styled);
  
But you often find yourself having to add additional logic, e.g. to scrub sensitive values, so it would probably end up closer to:

  const sensitiveEnv = [...];
  const envStr = Object.keys(envars)
        .filter(envar => !sensitiveEnv.includes(envar))
        .map(envar => `${envar}=${envars[envar]}`)
        .join(' ');
  const styled = chalk.dim(`$ ${envStr}`, 'node', args.join(' '));
  console.log(styled);
Re:Pipe Operator (|>) For JavaScript by cokeandpepsi on Friday January 20, 2023 @11:33AM (#34455514)
the refactored version of the example is much worse
Re:Pipe Operator (|>) For JavaScript by rektide on Friday January 20, 2023 @11:45AM (#34455741)
why? are you of a 'pointfree' opinion? what are your concerns? https://wiki.haskell.org/Pointfree

personally i detest pointfree syntax. having intermediate values makes it much easier to step through code with a debugger & see what is happening. and it gives the reader some name for what the thing is, which is incredibly useful context. the enablement of pointsfree styles is one of my main concerns about potential pipe operator syntaxes: the various syntaxes that have been raised often introduce implicit variables which are passed, and i greatly fear the loss of clarity pointsfree style brings.

maybe there's something beyond the pointsfree vs not debate here that i'm missing, that makes you dislike the refactored example. personally i greatly enjoy the flatness, the step by step production of intermediate values, each of which can be clearly seen, and then assembled in a last final clear step. that is much more legible to me than one complex expression.

Re:Pipe Operator (|>) For JavaScript by greggman3 on Friday January 20, 2023 @12:43PM (#34456724)
I agree that

(1) named intermediate values are sometimes more readable ... though I have examples where it's very hard to come up with names and not sure it helped

(2) debugging is easier.

For (2) though, this IMO is a problem with the debugger. The debugger should allow stepping by statement/expression instead of only by line (or whatever it's currently doing). If the debugger stopped at each pipe and showed in values (2) would mostly be solved. I used a debugger that worked by statements instead of lines once 34 years ago. Sadly I haven't seen once since. It should be optional though as it's a tradeoff. Stepping through some code can get really tedious if there are lots of steps.

Re:Pipe Operator (|>) For JavaScript by layer8 on Friday January 20, 2023 @01:04PM (#34457085)
Intermediate variables also have the benefit to make not just the last value available in a debugger view, but also previous values (stored in separate variables). Of course, a debugger could remember the last few values you stepped through, but without being bound to named variables, presentation would be difficult.
Re:Pipe Operator (|>) For JavaScript by 8note on Friday January 20, 2023 @03:35PM (#34459521)
It's hard to understand which statement the debugger has a break point set to when you can put many breakpoints on the same line

I have tools that can do it, but I'll still have a better time splitting out a variable for it, especially since what I really want is a log of all the intermediate values, so I can replicate what it's doing on paper

Re:Pipe Operator (|>) For JavaScript by ducharmdev on Friday January 20, 2023 @01:10PM (#34457160)
I think it really depends on the language.

In languages that more easily support repl-driven development (e.g. Clojure), I think this is less of an issue. If you have a handful of pure functions, you can quickly and easily execute them via the repl, so you get a lot of clarity as to what those intermediate values look like even if the functions are ultimately used in a more point-free style.

But on the other hand, this would be a nightmare in C# (what I use in my day job). Sure, you can execute arbitrary expressions while debugging C#, but IMO you can't really achieve the same clarity. I'd rather see intermediate values like you suggest since it's easier while debugging, vs a bunch of nested function calls.

Re:Pipe Operator (|>) For JavaScript by dns_snek on Friday January 20, 2023 @11:48AM (#34455806)
Do you mind elaborating? I find the refactored version significantly easier to understand than the original. Readability is one of the top priorities for me and I find the original example too clever, in a bad way.
Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @11:58AM (#34456011)
I dislike variables that are used just once. Sometimes they're a "necessary evil", but rarely. For "envStr" it's defensible IMHO as it splits up some of the complexity, but I would rather just use a helper function, which has the same "splits complexity" effect and is re-usable.

"styled" seems entirely pointless here.

Re:Pipe Operator (|>) For JavaScript by dns_snek on Friday January 20, 2023 @12:16PM (#34456326)
Extracting `envStr` is definitely the highest impact change for me. I dislike temporary variables too when they don't represent a meaningful intermediary result, but in this case I see them as a lesser evil. I agree that `styled` is more about personal preference.

This is why I'm happy to see the pipe syntax proposal, it avoids unnecessary temporary variables while simultaneously aiding readability.

Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @01:10PM (#34457155)
> This is why I'm happy to see the pipe syntax proposal, it avoids unnecessary temporary variables while simultaneously aiding readability.

The thing is I don't think it's all that much more readable. No matter which syntax you use, there's still the same number of "things" going on in a single statement.

I do have to admit I never worked with a language that uses |>, so I'm sure that with increased familiarly with this it would become "more readable" to me, but one has to wonder: just how many calling syntaxes does one language have to support? More syntax also means more potential for confusion, more ways to abuse the language/feature, more "individual programming styles", more argueing over "should we write it like this or that?", more overhead in deciding how to write something, harder to implement the language and write tooling for it, and things like that.

There is always a trade-off involved. The question to ask isn't "would this be helpful in some scenarios?" because the answer to that is always "yes" for practically any language feature. The question to ask "is this useful enough to warrant the downsides of extra syntax?" I'm not so sure that it is, as it doesn't really allow me to do anything new that I couldn't do before as far as I can see. It just allows me to make things that are already too complex a bit more readable (arguably).

Re:Pipe Operator (|>) For JavaScript by pcthrowaway on Friday January 20, 2023 @03:53PM (#34459786)
> I do have to admit I never worked with a language that uses |>

Have you never worked with Bash? It's basically the same thing

Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @04:02PM (#34459901)
Indeed it is, but it's kind of a different context than a "real" programming language. What works for one doesn't necessarily work well for the other.
Re:Pipe Operator (|>) For JavaScript by yamtaddle on Friday January 20, 2023 @06:51PM (#34461940)
Truly, one of the main reasons I might stop increasing the complexity of a bash one-liner and move it to a full shell script, or bail for Python, is specifically so I can turn those chains of pipes into imperative steps with temp vars so that they're actually legible and easy to reason about. I can't imagine why I'd want to go the other direction.
Re:Pipe Operator (|>) For JavaScript by yamtaddle on Friday January 20, 2023 @12:08PM (#34456191)
In this case I like that it gives you a hint about what's going on. "chalk.dim" sure doesn't.
Re:Pipe Operator (|>) For JavaScript by layer8 on Friday January 20, 2023 @12:58PM (#34456972)
Those variables help to document intent by naming the intermediate values. They also make step-debugging more convenient. In languages with type declarations, they also serve to inform about the type of the intermediate value, which otherwise is invisible in a pipe sequence.
Re:Pipe Operator (|>) For JavaScript by pharmakom on Friday January 20, 2023 @04:08PM (#34459962)
IDEs for languages with pipes allow break points on pipelines and can show inferred type annotations mid pipeline. Given the popularity of JS, this tooling will appear rapidly after pipe standardisation.
Re:Pipe Operator (|>) For JavaScript by whstl on Friday January 20, 2023 @12:59PM (#34456990)
This actually surprises me!

One habit introduced to my current team by a former co-worker involves having even more intermediate keys than that:

    const sensitiveEnv = [...];
    const envKeys = Object.keys(envars)
    const safeKeys = envKeys.filter(envar => !sensitiveEnv.includes(envar));
    const safeEnv = safeKeys.map(envar => `${envar}=${envars[envar]}`).join(' ');
    const styled = chalk.dim(`$ ${envStr}`, 'node', args.join(' '));
    console.log(styled);
In the beginning I wasn't a fan of it, as I do a lot of Haskell, and it's obviously unnecessary. But with time I learned to appreciate this kind of function for its simplicity and consistence.

Now, of course, with a pipe operator (or other similar constructions) you can get the consistency without the intermediate names.

Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @03:59PM (#34459849)
I just find it easier "thing" that happens is one self-contained statement, if that makes sense. Makes it easier to see what does what. I don't think one way is "better" or "worse" btw; all I can say to my brain, I find it harder to follow. This is what can make programming in a team hard.

I'm also one of those people that likes single-letter variables. I know some people hate it with a passion, but I find it very convenient. Just makes it easier to read as there's less to read.

I'm not smart enough to do Haskell, so I can't say much about that.

Re:Pipe Operator (|>) For JavaScript by whstl on Friday January 20, 2023 @04:05PM (#34459927)
Oh, a kindred spirit. I also love single-letter variables where they make sense. I have a math-heavy background, so they're totally cool for me, BUT I get why most programmers would hate 'em. I also like them since they were the "norm" in old C# LINQ code where I learned functional programming. If I were alone in the programming world I would have written the example above with single letter vars.

I agree with your remarks, there's no right or wrong, it's like tabs and spaces.

Btw I'm also not smart enough for Haskell, but it hasn't stopped me so far ;)

Re:Pipe Operator (|>) For JavaScript by rdez6173 on Friday January 20, 2023 @12:48PM (#34456833)
The refactored version is doing what pipes would do in a language that doesn't support pipes; it's reordering the statements into execution order rather than having to use a mental "stack" to grok the original version.

Given that the OP stated that they like the pipe syntax, and the refactored version illustrates the hoops you'd have to jump through without it, I guess your comment is just a strange way to agree with the OP?

Re:Pipe Operator (|>) For JavaScript by whstl on Sunday January 22, 2023 @02:31PM (#34481363)
Late reply, but I find that with a bit more of modernizing, and more consistent usage of chalk's arg-concatenation feature this can be turned into something much terser:

  const envs = Object.entries(envars).map(entry => entry.join('='));
  console.log(chalk.dim('$', ...envs, 'node', ...args));
I don't really have a point to make, perhaps just that there's often simplifications possible with extra creativity.
Re:Pipe Operator (|>) For JavaScript by BigJono on Friday January 20, 2023 @11:00AM (#34454868)
TC39 proposals often have rubbish real world examples that should never see the light of day in a JS codebase.

It makes me really question the judgement of the people that are working on this language, and it explains how some of the shittier proposals manage to slip in and why the good ones are misused all over the place in every real world codebase when this is the kind of guidance devs have on where to use fancy new features.

In a few years everyone is going to collectively lose their fucking mind once again and decide that ternaries are now the devil and every React component should be chock full of do expressions. I can see that coming clear as day. That might finally be enough to get me to throw in the towel if the also incoming decorator hell doesn't do it.

Re:Pipe Operator (|>) For JavaScript by nightpool on Friday January 20, 2023 @11:29AM (#34455444)
> TC39 proposals often have rubbish real world examples that should never see the light of day in a JS codebase.

This example was literally taken directly from real-world code in the React codebase (a script to call jest-cli). While you're correct that there are probably a lot of clearer and more readable ways to write this snippet, the fact of the matter remains that people write code exactly like these "real world examples" all of the time.

Re:Pipe Operator (|>) For JavaScript by BigJono on Friday January 20, 2023 @11:37AM (#34455594)
Yes and those people with a proven track record of writing awful code will now have another new tool to apply their valuable skills with. I can't wait.
Re:Pipe Operator (|>) For JavaScript by DarkNova6 on Friday January 20, 2023 @11:28AM (#34455434)
> It makes me really question the judgement of the people that are working on this language

Only now?

Re:Pipe Operator (|>) For JavaScript by stoned on Friday January 20, 2023 @11:04AM (#34454955)
I am still hoping that decorators might not pan out :fingers-crossed:
Re:Pipe Operator (|>) For JavaScript by recursive on Friday January 20, 2023 @11:41AM (#34455661)
Wait, what's wrong with decorators? They seem pretty nice in python.
Re:Pipe Operator (|>) For JavaScript by tracker1 on Friday January 20, 2023 @02:12PM (#34458186)
I like decorators as a concept... but there have been a couple different implementations now... the TypeScript version is probably the most broadly used, but there were others before it via Babel (formerly 6to5).

I was an early adopter of the original decorators proposal as well as the F#-style pipeline operators. The more time has moved on and other bits made it into JS proper, I'm far more inclined to stick to what's "in the box"... Have even considered just writing straight JS + ESM (modules). Of course, I also like JSX, though not sure of any proposals of how to get that "in the box" as e4x died on the vine and a lot of other efforts didn't gain much traction either.

Re:Pipe Operator (|>) For JavaScript by pwdisswordfisha on Friday January 20, 2023 @12:25PM (#34456427)
> some of the shittier proposals manage to slip in

Examples?

Re:Pipe Operator (|>) For JavaScript by wruza on Friday January 20, 2023 @06:35PM (#34461719)
React component should be chock full of do expressions

If the motivation behind these features are React components, javascript clearly lacks proper logic in array (and object) literals, like

  '[' if (cond) […]expr1 [else […]expr2] ']'
Although it seems pretty strange to add syntax only because some specific user interface library together with a specific language extension could benefit from it.
Re:Pipe Operator (|>) For JavaScript by MathMonkeyMan on Friday January 20, 2023 @11:17PM (#34463836)
Do you mean this?

    [cond ? expr1 : expr2]
Or maybe this:

    [(() => {/*code*/})()]
Re:Pipe Operator (|>) For JavaScript by wruza on Saturday January 21, 2023 @01:28AM (#34464371)
More like this:

  [...(cond ? [expr1] : [])]
Re:Pipe Operator (|>) For JavaScript by pharmakom on Friday January 20, 2023 @10:54AM (#34454758)
The Hack proposal is horrible imo because it doesn’t look like JS anymore. The F# proposal is 99% of the benefit whilst being actually approachable.
Re:Pipe Operator (|>) For JavaScript by masklinn on Friday January 20, 2023 @11:42AM (#34455674)
> The Hack proposal is horrible imo because it doesn’t look like JS anymore.

I mean it looks exactly like JS with an additional % placeholder.

Re:Pipe Operator (|>) For JavaScript by mkl on Friday January 20, 2023 @05:31PM (#34461011)
And a lot more like JS than the F# proposal.
Re:Pipe Operator (|>) For JavaScript by pharmakom on Friday January 20, 2023 @06:00PM (#34461344)
How so? JS already has operators, but placeholders is a totally new concept
Re:Pipe Operator (|>) For JavaScript by mkl on Friday January 20, 2023 @06:23PM (#34461595)
Is there another JavaScript feature that looks like a list of function names but which causes actions to be performed? Or operators that operate on both functions and values? The placeholders are very similar to variables, so do what they look like they do, and it's only the implicit definition that is new. The explicit placeholders feel much more like JavaScript to me than the implicit function calling of the F# proposal.
Re:Pipe Operator (|>) For JavaScript by pharmakom on Saturday January 21, 2023 @04:05AM (#34465033)
- functions and lambdas are already first-class values in JS

- we already have operators on values, such as +

- |> is just another operator on values

Re:Pipe Operator (|>) For JavaScript by galaxyLogic on Friday January 20, 2023 @11:20AM (#34455267)
I think we should have BOTH.

Use |> for the Hack proposal

and -> for F# -style.

Re:Pipe Operator (|>) For JavaScript by hajile on Friday January 20, 2023 @11:51AM (#34455873)
I'd far rather save that for an alternative switch expression with pattern matching.

    const slowSum = (lst: {x: number}[]) =>
      switch(list) {
        [{x}, ...y]   -> x + slowSum(y) //not tail recursive
        [{x}, {x: y}] -> x + y          //alias second x to y
        [{x}]         -> x              //handle length 1
        []            -> 0              //handle length 0
      }
Re:Pipe Operator (|>) For JavaScript by tracker1 on Friday January 20, 2023 @02:16PM (#34458244)
Having been watching, and a couple times playing with Rust... would definitely like a similar pattern matching system in JS. I still feel the C# syntax for this feels a bit alien `varname switch {...}`.
Re:Pipe Operator (|>) For JavaScript by pharmakom on Friday January 20, 2023 @02:02PM (#34458024)
As an F# developer who also does some JS and Java this would confuse the hell out of me! |> is the best operator
Re:Pipe Operator (|>) For JavaScript by grumpyprole on Friday January 20, 2023 @04:10PM (#34459980)
There's no need. The % placeholder can be used for a consise lambda syntax and would work with a F# application operator.
Re:Pipe Operator (|>) For JavaScript by epolanski on Friday January 20, 2023 @02:42PM (#34458649)
It absolutely is, but time and time again TC39 has followed few champions over the waves of people favoring F# pipes.

It's incredible to me TC39 would rather have this monstruosity over F# pipes which are actually pretty similar to how most pipes work and read in most functional languages including unix `|` one.

Re:Pipe Operator (|>) For JavaScript by WorldMaker on Friday January 20, 2023 @06:37PM (#34461750)
On the flipside, I think that this is still such an ongoing debate is part of why the pipeline operator is still stuck in Stage 2 and having trouble getting into Stage 3, despite being listed as a "priority" multiple times on and before 2020. TC-39 isn't blindly following anyone here, they seem to be dragging their heels hoping that someone comes along with an even better compromise between the styles.
Re:Pipe Operator (|>) For JavaScript by xigoi on Friday January 20, 2023 @04:50PM (#34460466)
Before ES6: “The arrow function proposal is horrible imo because it doesn’t look like JS anymore.”
Re:Pipe Operator (|>) For JavaScript by pharmakom on Friday January 20, 2023 @05:03PM (#34460642)
It’s a balance. I actually support the addition of the F# proposal, minus the await parts.
Re:Pipe Operator (|>) For JavaScript by antipurist on Friday January 20, 2023 @06:47PM (#34461889)
"Why did it take so long?" and "Pointless bloat!" reactions were much more common:

https://news.ycombinator.com/item?id=3780367

https://news.ycombinator.com/item?id=6418337

Re:Pipe Operator (|>) For JavaScript by Aldipower on Friday January 20, 2023 @11:11AM (#34455088)
Both examples are not good. They are both very unreadable and an example of slapping things together without to look on readability.
Re:Pipe Operator (|>) For JavaScript by scotty79 on Friday January 20, 2023 @11:28AM (#34455430)
> Neither seems very good to me, and the |> version doesn't really seem "less bad".

For me the piped version seems way better, way cleaner, with cleanly separated processing steps.

I don't like nested steps because for nesting multiple arguments functions your expression tends to grow in both directions and parts belonging to the same step tend to end up really far from one another.

% is short so it keeps parts of the same processing step together.

Re:Pipe Operator (|>) For JavaScript by thdc on Friday January 20, 2023 @11:09AM (#34455045)
I do prefer the piped version mainly because it removes annoying nesting but that's not high on my prioritized list of discomforts. The issue of deeply nested function calls is a thing, but I just use some temp variables to avoid it when it really starts looking ugly.

Then again, this is my typical opinion to a lot of the proposals - I see what this is useful for but I haven't experienced enough pain to really argue for it. However, if it does make it into the spec then I will use it probably because it's there.

I also recognize my stance as one that not many people like in other contexts because it can be interpreted as me not looking to improve my situation. But on the flip side I think cluttering the language specification with a lot of superficial syntactic sugar is a mistake.

Re:Pipe Operator (|>) For JavaScript by jakear on Friday January 20, 2023 @11:16AM (#34455210)
> Everyone wants something different, and if you just implement the "top 5 most requested features" you're going to end up with some frankenbeast of a language.

Very much this. They need a new question on the survey "does JavaScript need new syntax or can we just leave it alone and work on perf/tooling/etc. of the existing stuff without throwing a bunch of new junk in"?

Re:Pipe Operator (|>) For JavaScript by dmix on Friday January 20, 2023 @11:01AM (#34454895)
Just because pipe's aren't the ideal solution for that convoluted example they decided to list doesn't mean they aren't still extremely useful for a consistent set of problems. Like anything they can be abused to make code less readable.

I also have a feeling this doc lists every sort of usecase, not because they are advertising it as "always the better version", but because it's a design doc that needs to factor in edge cases, such as using a pipe following chained function calls.

Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @11:20AM (#34455283)
I'm just using the example they posted in the README as an "before-after". I think that's a reasonable thing to do when evaluating "do I think this would be a good feature?" Blame the author(s) of that document if you don't think it's a good example.
Re:Pipe Operator (|>) For JavaScript by dmix on Friday January 20, 2023 @12:43PM (#34456734)
That seems to be missing the point of the document then. Before/after in a design doc isn't "this is a better way to do it".
Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @01:14PM (#34457228)
What is the point then?
Re:Pipe Operator (|>) For JavaScript by dmix on Friday January 20, 2023 @01:37PM (#34457617)
I don't see design docs as a tutorial on how to be a better programmer using a new syntax, the goal is to flesh out a new concept built on some fundamental ideas.

You cherry picked one example of a tangled/messy block of code that they used to communicate specific idea around "left to right" comprehension and flow of the data using the new syntax. For that specifically it did a fine job.

But that doesn't mean that's the way you should be writing code in the first place, given it started with a mess and only used one piece of syntax to change it.

I will admit it's a poor example to open with. But for a design doc about exploring and debating ideas it's fine.

Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @02:04PM (#34458064)
The way I read the proposal is that they used a real-world example from a commonly used codebase (React) to demonstrate how this feature would improve it. I think that's a good approach as features are intended to address real-world concerns, and concrete real-world examples help with that.

I don't think it's fair to say it's "cherry picking" to focus on the example they focus on themselves. They have a few other examples too, but I would say "I don't see how [NEW] is better than [OLD]" for many of those as well (and for some, I think the [NEW] is significantly worse).

Re:Pipe Operator (|>) For JavaScript by dmix on Friday January 20, 2023 @11:56PM (#34464024)
Considering it was their opening example (which they reiterated multiple times) I will concede it was a poor choice. Since yes one of the top goals is selling the general idea. So it's fair the general audience would take it at face value, especially when they use it multiple times as a real world use case, it is hard to take it any other way.

Plus the doc is #1 on HN after all, which could IRL push it beyond a proposal stage if done right.

Re:Pipe Operator (|>) For JavaScript by NhanH on Friday January 20, 2023 @11:08AM (#34455027)
Method chaining is better, but you need the library/class/ code to support it. If you got a bunch of function it can’t help you. Pipe operator is useful for when you use other people’s code.

On the other hand, pipe is less useful when you don’t have partial application of function built-in. So yeah I think this is not worth it.

Re:Pipe Operator (|>) For JavaScript by travisgriggs on Friday January 20, 2023 @11:17AM (#34455220)
This works when your language doesn’t have an implicit “return nothing” as it’s default. Nothing says “imperative” like “this routine may or may not take input, but you ain’t getting nothing back out of it.”

Ironically, OO gets thrown under the bus a lot lately because it ain’t functional. But in reality, early OO languages like Smalltalk and CLOS were much more functional in this regard, you always had an implicit return of self, which could be chained easily.

I (over)use the piping operator (|>) in Elixir a lot. I just like the way it reads. But one thing I don’t love, is that it’s not an easy sequence to type.

Re:Pipe Operator (|>) For JavaScript by OkayPhysicist on Friday January 20, 2023 @12:25PM (#34456435)
Elixir's pipe mechanics probably aren't a great model for implementing pipe operators in existing languages. A large part of what makes |> work in Elixir is the steadfast commitment to f(most_likely_to_be_piped_param,other,params) argument ordering in the standard library.
Re:Pipe Operator (|>) For JavaScript by epolanski on Friday January 20, 2023 @02:44PM (#34458688)
fluent apis are a matter of preference.

I personally find pipe style much more readable.

Re:Pipe Operator (|>) For JavaScript by progx on Friday January 20, 2023 @11:03AM (#34454926)
For me not. In the Pipe example you must read first that something is done with the object and that it will be output at the end.

If i read a code and i want to now what it will do, i wanna first read that it will output something. If that is what i search for, i read the nested code.

With the pipe style i waste more time, even if the code looks clearer.

I not overused example could look like this:

  console.log(
    Object.keys(envars)
      .map(envar => `${envar}=${envars[envar]}`)
      .join(' ')
    |> `$ ${%}`
    |> chalk.dim(%, 'node', args.join(' '))
  )
If i don't care about console.log, i don't have to read the nested code.
Re:Pipe Operator (|>) For JavaScript by tgv on Friday January 20, 2023 @11:20AM (#34455282)
So their argument in favor of this fugly new operator is that some people write unreadable code? That's not the language's fault. As they say, you can write FORTRAN in any language. This just gives them a new tool to make things even worse.

     chalk.dim(Object.keys(envars)
       .map(envar => `${envar}=${envars[envar]}`)
       .join(' ')
       |> `$ ${%}`, 'node', args.join(' '))
     |> console.log(%);
And it doesn't even work on objects. Lame. I know the reason: JS has no typing. Still is lame.
Re:Pipe Operator (|>) For JavaScript by 8note on Friday January 20, 2023 @03:43PM (#34459638)
I'm trying to compare this to the jQuery kinda syntax

X

.this()

.that()

.then()

.do()

.a()

.thing()

And I expect this to let me keep that chain going for when I need to run a static function against the chain

X

.this()

.that()

.then()

.do()

.a()

.thing()

|>JSON.stringify(%)

Re:Pipe Operator (|>) For JavaScript by mkl on Friday January 20, 2023 @05:35PM (#34461055)
To format code as code, indent two spaces: https://news.ycombinator.com/formatdoc
Re:Pipe Operator (|>) For JavaScript by kzrdude on Friday January 20, 2023 @11:17AM (#34455229)
You have nested backticks there. Is this really real code?
Re:Pipe Operator (|>) For JavaScript by arp242 on Friday January 20, 2023 @11:25AM (#34455364)
Yes, you can do that in lambdas:

    > `${50}: ${[1,2,3].map(a => `${a+1}`)}`
    '50: 2,3,4'
Whether that's a good idea or clear code is another issue. But it's allowed.
Re:Pipe Operator (|>) For JavaScript by Joker_vD on Friday January 20, 2023 @11:12AM (#34455125)
Some people, it seems, just love to write things in A-normal form but dislike naming temporary variables. Solution: pipe operator.
Re:Pipe Operator (|>) For JavaScript by DarkNova6 on Friday January 20, 2023 @11:27AM (#34455404)
Wait, design by committee is not a good thing? Gasp

I can only hope this leads to Javascript becoming even more unbearable. Perhaps only this can weaken Google's resistance to WASM.

Re:Pipe Operator (|>) For JavaScript by mschuetz on Friday January 20, 2023 @11:52AM (#34455890)
All of the examples look unreadable and hard to debug to me. Why not something like this rather than one massive nested instruction?

    let keys = Object.keys(envars);
    let text = keys.map(envar => `${envar}=${envars[envar]}`).join(" ");
    console.log(chalk.dim(`$ ${text}`), "node", args.join(' '));
That way you can easily inspect and verify the intermediate values at runtime. Helpful for you to see if your code works as expected, helpful for others to see what the code is doing.
Re:Pipe Operator (|>) For JavaScript by hinkley on Friday January 20, 2023 @12:28PM (#34456473)
Bad examples can doom a project. It's amazing how much time people can spend on a solution while completely ignoring the documentation.

Pipes are probably better used on a set of operations that takes input and runs multiple functions on the input, rather than fiddling with string concatenation multiple times.

What do we use multi-pipes for in unix? I can't recall the last time I used one where the middle action wasn't a filter of some sort. grep -v to remove lines, or colrm or awk print to cherry-pick fields from a multi-field line. Once in a very long while I need to do three commands with filters between them. Beyond that it's too complicated and I make a script to handle several of the steps.

Re:Pipe Operator (|>) For JavaScript by lucideer on Friday January 20, 2023 @12:02PM (#34456080)
The issue with taking examples from real-world code & converting them is that there's no guarantee the real-world code is good. It usually isn't, so you're comparing bad with bad.

A more aggressive reformulation would be to prefix the original code with

  const envOutput = Object.keys(envars).map(envar => `${envar}=${envars[envar]}`).join(' ');
  const argsOutput = args.join(' ');
Leaving the example being converted as simply:

  console.log(chalk.dim(`$ ${envOutput}`, 'node', argsOutput));
vs

  envOutput |> `$ ${%}` |> chalk.dim(%, 'node', argsOutput) |> console.log(%);
This more clearly highlights the obvious limitations of pipelines - piping envOutput but not 'node' nor argsOutput is a jarring syntax-mix here. Though I think it offers some hope for them working well in other scenarios - possibly in curry-heavy applications.
Re:Pipe Operator (|>) For JavaScript by scotty79 on Friday January 20, 2023 @01:02PM (#34457045)
It's not jarring. It expresses what is the subject that's being processed and what are additional parameters of the processing steps. This allows to keep all parameters of each processing step together and processing steps easily visually separable.
Re:Pipe Operator (|>) For JavaScript by lucideer on Friday January 20, 2023 @01:18PM (#34457290)
> It's not jarring. It expresses what is the subject that's being processed and what are additional parameters of the processing steps.

Only if the first parameter of the function is the sole subject & subsequent parameters are "additional". Which isn't the case in this example: all params are equal subjects.

Re:Pipe Operator (|>) For JavaScript by scotty79 on Friday January 20, 2023 @01:57PM (#34457943)
Right. `chalk.dim()` is probably not the best thing to use as an example for this.

But you can still think about this as merging in two additional pipes into the one you are processing. So 'node' and argsOutput are just very short pipes that you are merging into the flow of current one.

Btw... chalk API feels super weird.

Re:Pipe Operator (|>) For JavaScript by johnny22 on Friday January 20, 2023 @12:08PM (#34456185)
Is that how they really do it? I haven't actually seen that happen. There's no reason not to take popularity into account for some measure, as long it's not the ONLY thing you take into account.
Re:Pipe Operator (|>) For JavaScript by masswerk on Friday January 20, 2023 @12:23PM (#34456404)

  > I also feel this:
  >> In the State of JS 2020 survey, the fourth top answer to “What do you feel is currently missing from JavaScript?” was a pipe operator.
  > Is the wrong way to go about language design.
Let's call it Signor Rossi language design…

"Signor Rossi cosa vuoi? … E poi, e poi, e poi" (Viva la felicità by Franco Godi [1])

[1] https://www.youtube.com/watch?v=UrKKMtjNWCI

Re:Pipe Operator (|>) For JavaScript by vorotato on Friday January 20, 2023 @12:57PM (#34456964)
This and, they probably didn't mean the pipe operator from the niche language "hack".
Re:Pipe Operator (|>) For JavaScript by runarberg on Friday January 20, 2023 @12:47PM (#34456810)
During the 2020 survey there were two versions of this operator on the table smart mix and F#. A few months later the committee advanced a third option Hack, which is kind of like smart-mix but always requires the placeholder token.

I suspect that many developers expressed their desire for this operator under the believe that it would make their style of programming easier, which F# indeed does for many code bases, particularly those that use libraries such as fp-ts or rxjs.

However the advanced version fails to deliver that

Re:Pipe Operator (|>) For JavaScript by scotty79 on Friday January 20, 2023 @01:05PM (#34457106)
I'll bite:

    let $= Object.keys(envars)
    .map(envar => `${envar}=${envars[envar]}`)
    .join(' ')
    $= `$ ${$}`
    $= chalk.dim($, 'node', args.join(' '))
    $= console.log($);
This is possible in current JS syntax.

You can also cram it into one line with semicolon:

    let $= Object.keys(envars)
    .map(envar => `${envar}=${envars[envar]}`)
    .join(' ') ;$= `$ ${$}` ;$= chalk.dim($, 'node', args.join(' ')) ;$= console.log($);
So it's basically Hack syntax for pipes with just ;$= instead of |> and $ instead of %. And you need to 'mark' the beginning of the pipeline with `let $=`

Additional 'benefit' is that until you leave the scope you can access output of the last pipe through $.

You can always use ;$= for consistency and pre-experess you intent to use the piping in the current scope by doing `let $;` ahead of time:

    let $;

    ;$= Object.keys(envars)
    .map(envar => `${envar}=${envars[envar]}`)
    .join(' ')
    ;$= `$ ${$}`
    ;$= chalk.dim($, 'node', args.join(' '))
    ;$= console.log($);
Full disclosure, I hate all of the above but I love Hack syntax with |> and %.

Also any valid JS name is good:

    let _= Object.keys(envars)
    .map(envar => `${envar}=${envars[envar]}`)
    .join(' ')
    _= `$ ${_}`
    _= chalk.dim(_, 'node', args.join(' '))
    _= console.log(_);
so you have a lot of flexibility in your pipes. :-D

To better confer the direction of the pipe you might even use the letter that is oriented to the right:

    let D;
    ;D= Object.keys(envars)
    .map(envar => `${envar}=${envars[envar]}`)
    .join(' ')
    ;D= `$ ${D}`
    ;D= chalk.dim(D, 'node', args.join(' '))
    ;D= console.log(D);
Re:Pipe Operator (|>) For JavaScript by notpushkin on Friday January 20, 2023 @03:13PM (#34459141)
;D
Re:Pipe Operator (|>) For JavaScript by scotty79 on Friday January 20, 2023 @03:38PM (#34459582)
Perfectly legal syntax. ;D
Re:Pipe Operator (|>) For JavaScript by moogly on Friday January 20, 2023 @04:03PM (#34459912)
This is the code equivalent of that "illegal LEGO techniques" thing to me.
Re:Pipe Operator (|>) For JavaScript by sirsinsalot on Friday January 20, 2023 @01:28PM (#34457458)
They're all horrific
Re:Pipe Operator (|>) For JavaScript by jameshart on Friday January 20, 2023 @01:44PM (#34457723)
The thing I dislike about it most is the constantly-rebound % variable. It means something different in each line. In this case they have elected to keep it as a string throughout the pipe, but this ‘more pipey’ version of the code has it start out as an array then turn into a string halfway through the pipe, which feels dangerous (and is presumably why they didn’t take the example this far):

    Object.keys(envars)
      |> %.map(envar => `${envar}=${envars[envar]}`)
      |> %.join(' ')
      |> `$ ${%}`
      |> chalk.dim(%, 'node', args.join(' '))
      |> console.log(%);
Re:Pipe Operator (|>) For JavaScript by tracker1 on Friday January 20, 2023 @02:23PM (#34458356)
Not really... F#-style pipeline syntax would be a bit more explicit about it, assuming you could use % for a variable name...

    Object.keys(envars)
      |> % => %.map(envar => `${envar}=${envars[envar]}`)
      |> % => %.join(' ')
      |> % => `$ ${%}`
      |> % => chalk.dim(%, 'node', args.join(' '))
      |> % => console.log(%);
To be honest, I've pretty much given up the hopes that TC39 would actually resolve pipelines and decorators at this point... I think it's been around a decade now.
Re:Pipe Operator (|>) For JavaScript by jameshart on Friday January 20, 2023 @02:54PM (#34458851)
But then why would you call all those different variables ‘%’?

Reading this version though I also notice something else that the F# style enables that the Hack style doesn’t which is that it supports destructuring. So in F# style, I can more easily make pipe steps that pass on multiple values in a structured object or array, then access them easily down-pipe.

Re:Pipe Operator (|>) For JavaScript by tracker1 on Friday January 20, 2023 @02:59PM (#34458932)
Unfortunately F# pipelines have been rejected a few times by TC39 to advance... I used it for a while via Babel/6to5, but I gave up (like with decorators) after many years of no advancement. I doubt I'll see either any time soon.
Re:Pipe Operator (|>) For JavaScript by wheelerof4te on Friday January 20, 2023 @01:53PM (#34457880)
SELECT 'Jerk' FROM jerkings_tab;

Is this Perl?

DROP jerkings_tab;

Is this really Perl?

Re:Pipe Operator (|>) For JavaScript by ryanmcbride on Friday January 20, 2023 @01:54PM (#34457883)
I feel like your first example was written kind of in bad faith but still, literally yes your first example is better than your second.
Re:Pipe Operator (|>) For JavaScript by ravenstine on Friday January 20, 2023 @02:18PM (#34458285)
The flaw with that approach to language development is that there's no limiting factor.

Can you imagine a survey where everyone says they're satisfied with the language as-is? Of course not. That's statistically impossible. Even if 99% of the needs of developers are satisfied by a language, people are going to eventually answer that they'd like something that the language doesn't have, and that's always the case.

Let's say JavaScript implemented nearly every single language feature that's ever been invented. That is except the goto statement. Upon being surveyed on what they think is currently missing from JavaScript, a significant number of developers will have to respond with goto. Does that mean JavaScript is actually "missing" goto and that it was a mistake that it was never implemented in the first place? Of course not.

Re:Pipe Operator (|>) For JavaScript by rubyist5eva on Friday January 20, 2023 @02:31PM (#34458477)
As somone that use to write a lot of functional-style code (in ruby), and generally prefers functional style, and have created many many many "pipelines" like that in ruby code - I've actually started to "regress" to "status-quo" (as the article puts it) mostly because I work with developers that don't understand functional style and it just becomes point of contention in review that I just don't care about getting into anymore. I can see this same kind of thing happening with this operator in JS-land (I may be wrong, haven't written any significant javascript in years, but people tend to be stubborn).

I just write things as stupidly as possible now, and just do the second one even though there are nicer "ruby-ways" to do them - maybe this is "bad" but I find it easy to read and grok...and it doesn't cause arguments during review <.<

Re:Pipe Operator (|>) For JavaScript by stouset on Friday January 20, 2023 @04:07PM (#34459945)
> Is this… ${new-style} really better than… ${old-style}?

Yes! A hundred thousand times yes!

I have not seen this syntax in JavaScript before, but just by having the vague notion that it's pipe-like, I was able to generally understand what was happening within seconds of reading it. I'd have to read up on the syntax a bit to confidently write code in this style, or perhaps to fix a bug (does "${%}" do what I think it does) but I can quite literally comprehend the author's intent almost at almost the same speed as I can read.

    1. get all the keys of envars.
    2. convert every key into a "var=value" format.
    3. put a space between them all
    4. stick a dollar sign in front of the whole thing
    5. no clue what the `chalk` library is for?
      a. this *appears* to prefix a "node ${args}" call with the previously-created environment variable bits
      b. that tracks with what we've seen so far
      c. close enough for now
    6. log the whole thing
Note that even without knowing what chalk is or does, the flow of everything makes it extremely clear what exactly the high-level outcome is supposed to be. We're building up a string like "$ FOO=bar BAZ=qux node --arg thing --arg2 more_args". We're doing something fancy with it that I don't quite know about just yet, but the above knowledge makes it very easy to fill in that gap.

With the second one, I have to construct a tree in my head

    1. console.log…
      a. the result of chalk.dim, which is
        i. all the env vars
        ii. mapped to key=value format
        iii. joined by a space
      b. ^ actually do chalk.dim on that thing above
        i. sorry, back up, there were some additional arguments
      c. ^ actually do chalk.dim on the above with 'node' and space-separated args
        i. I think this concatenates them?
        ii. double-check [1.a] to confirm
        iii. did I miss `args` defined somewhere in [1.a]?
          A. no, it's apparently inherited from scope
    2. ^ actually log all the above
      a. wait is this a correct reading, based on reassembling the above?
The confusion is compounded by not knowing the details of chalk. I have to jump backwards and reason about what the result of a non-linear chunk of steps is to make sure my guess is consistent.

I have no opinion on the merits of this particular syntax, its implementation details, or in comparison to alternate proposals of similar ideas. I'm sure there's worthwhile debate to be had on those details. But from a high level, I'm a fan. My head is not a meat-based tree traverser and I'm guessing most people's isn't either. Human brains are big fans of linear narratives. While I love movies and shows like Memento and Westworld, this kind of disjoint storytelling is quite literally done for the purpose of generating confusion and not for promoting comprehension.

Re:Pipe Operator (|>) For JavaScript by cyberlock on Friday January 20, 2023 @04:18PM (#34460060)
Location hacked :Dianamaya020@gmail.com-configuration-reg-up-from-Cyberlock-sucesfully Device-samsunggalaxy-power-Network-223b/s-cord-cianjur-cibinong-girijaya-gunungbitung-leles<gpslocation-complete> Done
Re:Pipe Operator (|>) For JavaScript by quickthrower2 on Friday January 20, 2023 @05:30PM (#34460995)
I don’t like complex nesting inside the string though. That might be a nitpick as you can split that out without the pipe operator.
Re:Pipe Operator (|>) For JavaScript by mkl on Friday January 20, 2023 @05:48PM (#34461200)
JavaScript has been a frankenbeast of a language right from its inception, by design.

However, the 5th most requested feature in that poll is somehow "functions", and "sanity" also appears in the results, so this particular source may not be a good one.

Re:Pipe Operator (|>) For JavaScript by aabbcc1241 on Tuesday January 24, 2023 @11:14PM (#34514331)
Within the current js syntax, you can make the code looks readable with a chain or pipe with a simple function https://github.com/beenotung/tslib/blob/master/src/pipe.ts

You can even use an array if you don't need to peek the value in the middle of a chain of operations

Example:

    createChain(
      Object.entries(envars)
      .map(([key, value]) => `${key}=${value}`)
      .join(' ')
    )
      .map(keys => `$ ${keys}`)
      .map(pattern => chalk.dim(%, 'node', args.join(' ')))
      .use(line => console.log(line))

In each step, you can name the intermediate result accordingly to it's meaning, should be more readable than calling it %