Live data from Hacker News

Pipe Operator (|>) For JavaScript

github.com

311–320 of 437 posts

Re: Pipe Operator (|>) For JavaScript

#311
post #27

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). N…

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.

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

#312
Seems to me that someone "stole" it from F#. F# probably also take this idea from some unknown (to me) language. Here a similar idea in C++ https://www.fluentcpp.com/2019/10/18/piping-to-and-from-a-st...

This is generally a weakness of text based programming languages, that you cannot easily express graph flows like:

    / B1 \
 A>-|    | -> C
    \ B2 /
|> operator only solves the problem for non-branched flows like A -> B -> C making them more readable by removing nested calls.

In theory you can create something similar using JS OOP by attaching e.g. map/use(func) methods to every prototype:

  function use(func) { func(this); return this; }
  function map(func) { return func(this); }
and then:

  (1).map(n => n+1)
    .use(console.log)
    .map(n => "n = " + n)
    .use(n => console.log("str = $n"));
Introducing a new operator instead of a library is a huge effort. I don't think this proposal will succeed, especially that current custom operator support in JS is nil.

Re: Pipe Operator (|>) For JavaScript

#313

Earlier quoted context omitted.

Sometimes intermediate values either don't have domain specific meanings or the meaning is obvious from the function name that returns this temporary value. Then naming it is just noise. If your bake() function was rather named createBakedCake() than naming returned value bakedCake just increses reader fatigue through repetition. Same way Random random = new Random(); in C# is worse than var random = Random();

> Sometimes intermediate values either don't have specific meanings or the meaning is obvious from the function name that returns this temporary value. I don't necessarily disagree with this. But even granting that this is true: congrats, you've just found the worst part of giving these intermediate steps a name! Like, that's the worst case example of the cost side of the tradeoff we're discussing here. And it's not…

> But even granting that this is true: congrats, you've just found the worst part of giving these intermediate steps a name!

Yes. But given that people would usually put you on a stake for naming function bake() because it doesn't tell anything about what the function expects or returns and bare minimum about what it does, this use case scenario is what happens very often, because naming your function in a very informative manner is very important because they are a part of the API.

If you really have functions like bake() or pour() in your code esp in weakly typed language then for the love of God, yes, please name the variables that you pass there and get from them always and as verbosely as possible.

Don't get me wrong, I'm very fond of naming intermediate things too. And with helpful IDE it can even tell you the types of intermediate things so you can better understand the transformations that the data undergoes as it flows through the pipeline.

But sometimes type, that IDE could show also automatically in |> syntax is even more important than the name for understanding. VS Code does something like that for Rust for chaining method calls with a dot. Once you split dot-chain into multiple lines it shows you what is the type of the value produced in each line.

My personal objection to naming temporary values too much in a pipeline is that it obscures distinction between what's processed and what are just options of the each processing step. But I suppose you might keep track of it by prefixing names of temporary values with something.

> Or maybe you want to just start with the unnamed nested or chained calls, and when you need to read or debug or refactor or test your code you pay the "naming things" price tag at that point.

Yeah, that's usually what I do. I start with chains and split them and pay for the names as I go.

> That's often the first thing I do when I come across code with a dearth of names, I just give everything a boring, uncreative temporary name, and then I can do whatever work I showed up to this code to do.

I'm also splitting and naming stuff in that case and checking types along the way. But I prefer that to encountering the code named verbosely and wrongly. Then I need to get rid of the names first to see the flow then split it again sensibly. Of course I don't usually commit those changes in shared environments. Only in owned, inherited ones or if the point of my change is to refactor.

Granted that chaining class member accessor mostly covers up this problem of naming intermediate things if you use classes. That's why we even survived without pipe syntax. But since we would like to move away from classes a bit to explore other paradigms maybe it's time?

Re: Pipe Operator (|>) For JavaScript

#314
post #72
post #27

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). N…

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.

fluent apis are a matter of preference.

I personally find pipe style much more readable.

Re: Pipe Operator (|>) For JavaScript

#315

Can someone remind me again why there's never been movement to add a second modern language to web-browsers? JavaScript was created in a weekend and then stuff tacked on for the last 28 years. We know so much more about how to create programming languages today than we did then, and the whole "Year of the Linux Desktop" has become a WebAssembly meme now every year since its introduction six years ago, with it getting…

Because there's not that much wrong with modern JS, with the "created in a weekend" mantra being wholly irrelevant.. Back when JS was trash there was was Coffeescript and other lesser used alternatives, and Google tried to push Dart but nobody cared. Today is pretty much only JS and its superset TS and that's not an accident. They're perfectly productive. My annoyance with JS is almost entirely to do with Node, other…

I know a few people don't like it... but I've really enjoyed the Deno take on things for JS/TS runtime. While I'd prefer more native deno, the npm/node compatibility integration has made it really useable.

As for GP, you're right... there have actually been MANY attempts at other languages for in-browser. In the end, the JS runtime has been hardened and all other roads have led to WASM being the second target. I still remember a lot of people using VBScript in IE. I was an outlier in that I used JScript for classic ASP.

Re: Pipe Operator (|>) For JavaScript

#316

For languages, which do not have built-in the power to change themselves, in many cases it might be better to stick to their feature set, instead of introducing even more language concepts. Look at how much work is involved to get something as simple as pipelines. As if they will ever find the right syntax for everyone. If we used a normal function we might have to include a library or a dependency or heck, just take…

I understand the hassle around pipelines.

Entire ecosystems like `fp-ts` or `effect-ts` are regularly used with pipeable APIs and no one beats an eye.

The only thing that was needed was a syntax that would've allowed this:

    pipe(
      "foo ",
      capitalize, // "FOO "
      trim, "FOO"
      shout, "FOO!"
      console.log, undefined
    )
to not require `pipe`.

      "foo "
      |> capitalize
      |> trim
      |> shout
      |> console.log
Why `pipe`? Because otherwise you need to write it like that:

`console.log(shout(trim(capitalize("foo"))))` which is unnatural as you need to read the chain in reverse order and is especially hard in less trivial cases than a sequential string manipulation.

Re: Pipe Operator (|>) For JavaScript

#317

Earlier quoted context omitted.

Exactly. As the proposal contemplates this alternative, it claims: > But there are reasons why we encounter deeply nested expressions in each other’s code all the time in the real world, rather than lines of temporary variables. And the reason it gives is: > It is often simply too tedious and wordy to write code with a long sequence of temporary, single-use variables. Sorry, but...that's the job? If naming things is…

and yet looking through code from the place you work I see something like this let field = ve.instanceContext.replace(/(#\/)|(#)/ig, "").replace(/\//g, ".") Which you apparently claim should be const fieldWithHashMarksUnesacped = ve.instanceContext.replace(/(#\/)|(#)/ig, ""); const field = fieldWithHashMarksUnesacped.replace(/\//g, ".") https://github.com/mirusresearch/firehoser/blob/46e4b0cab9a2... and this return m…

Thanks for taking the time to look and reply.

In your first find, yes, your modification helps me understand that code much more quickly. Especially since I haven't looked at this code in several years.

In that case, patches welcome!

In your second case, as the sibling comment explained, I'm not opposed to chaining in all cases. But if the pipe operator is being proposed to deal with this situation, I'm saying the juice isn't worth the squeeze. New syntax in a language needs to pull its weight. What is this syntax adding that wasn't possible before? In this case, a big part of the proposal's claim is that this sequential processing/chaining is common (otherwise, why do we care?), confusing (the nested case I agree is hard-to-read, and so would be reluctant to write), or tedious (because coming up with temporary variable names is ostensibly hard).

I'm arguing against that last case. It's not that hard, it frequently improves the code, and if you find cases where that's not true (as you did with the `moment` example above) the pipe operator doesn't offer any additional clarity.

Put another way, if the pipe operator existed in JS, would you write that moment example as this?

    return moment(input)
      |> %.utc()
      |> %.format('YYYY-MM-DD HH:mm:ss');
And would you argue that it's a significant improvement to the expressiveness of the language that you did?

Re: Pipe Operator (|>) For JavaScript

#318
post #53

Temporary variables are often tedious? I have found that well named temporary variables are the only clear way to comment code without actually writing the comment. The version with temporary variables is much easier to understand without having to read the rest of the code.

Exactly. As the proposal contemplates this alternative, it claims: > But there are reasons why we encounter deeply nested expressions in each other’s code all the time in the real world, rather than lines of temporary variables. And the reason it gives is: > It is often simply too tedious and wordy to write code with a long sequence of temporary, single-use variables. Sorry, but...that's the job? If naming things is…

> The aphorism "There are two hard problems in computer science: cache invalidation, and naming things." is not an argument to never cache and never name things.

Sure, it can’t be completely eliminated, but why not do less of a thing that’s hard, when it can be avoided?

Values have a “name”, whether it’s a variable ‘keysAsString’ or the expression ‘keys.join(' ')’. The problem with keysAsString is that you have to type it twice, once to define it and again to use it. It’s also less exact, because it’s a human-only name, not one that has a precise meaning according to the rules of the language. (E.g. a reader might wonder what the separator between the keys was - if you don’t store it in a variable, then the .join “name” tells you precisely right at the site it’s used.) Making the variable name more precise implies more tedium in the writing and reading.

If the value is used twice or more, I would usually say storing it in a well-named variable is preferable, but if it’s cheap or optimizable by the compiler I might still argue for the expression.

This may be a irreconcilable split between different types of thinkers, perhaps between verbal and abstract.

Re: Pipe Operator (|>) For JavaScript

#319

Can someone remind me again why there's never been movement to add a second modern language to web-browsers? JavaScript was created in a weekend and then stuff tacked on for the last 28 years. We know so much more about how to create programming languages today than we did then, and the whole "Year of the Linux Desktop" has become a WebAssembly meme now every year since its introduction six years ago, with it getting…

WebAssembly is just what you want, a second "modern" language that works in browsers. It hasn't reached 100% of its potential just yet, as there are some things missing for that (like DOM access) but once the language is feature complete, I'm sure most languages will have some sort of "Lang to WASM" tooling that'll allow you to write React apps in Ruby or whatever, if you so wish. Stuff like that takes time though, s…

There's a few options out there if you don't mind being an early adopter. Most interactions via DOM bridging are slower than actual React... but it's kind of cool.

Yew (Rust) is one that I've been following with interest, the hello world examples are interesting enough. I know people that have been liking the direction of Blazor (C#) more, but it has a larger initial payload, that I don't care for, it's also closer to SSR approach in the browser.

The problem with both, IMO, is that they don't have a good UI library/toolkit. I find mui.com (with React) pretty much the best browser ui framework I've experienced (since 1996). To me, the first language + component library that targets WASM and that level of components will likely win.

Flutter is probably the closest example I'm aware of, though afaik it's JS as the browser target, not WASM, but wouldn't be surprised if this changes assuming DOM interop for WASM becomes better performing.

Re: Pipe Operator (|>) For JavaScript

#320
post #23

Earlier quoted context omitted.

No compatibility is broken, old scripts will keep on working just fine. Scripts written for the new syntax won't work in old browsers, but that's the nature of evolving standards anyway.

> Scripts written for the new syntax won't work in old browsers, And critically browsers are - for the most part - much more in sync these days across the board. A lot of web devs got burned through the years of IE6-IE11 and have a natural distaste for browser level changes. Pipes have been (formally) debated for 5yrs now by the JS people, so they aren't exactly being non-conservative about this one.

Unfortunately. If your web page need to deal with Chinese Android phones, you still need to deal with old browsers.

Their android system somehow always shipped with broken auto-update of webview or chrome.

Which results in people open your webpage with quite old browser version.

Post reply on HN