Live data from Hacker News

Pipe Operator (|>) For JavaScript

github.com

231–240 of 437 posts

Re: Pipe Operator (|>) For JavaScript

#231

Earlier quoted context omitted.

I struggle to think of real-world examples where I've just needed to chain and chain and chain values of different types more than a handful of times. The claimed need for the pipe operator is this construction: function bakeCake() { return separateFromPan(coolOff(bake(pour(mix(gatherIngredients(), bowl), pan), 350, 45), 30)); } The piped code looks like: function bakeCake() { return gatherIngredients() |> mix(%, bow…

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 that big a cost! Like, of all the code you write, how much of it fits this case? Where you're writing a function where there's a lot of sequential processing steps in a row with no other logic between the steps AND the intermediate state doesn't have any particular meaning?

In that worst case, you have a little extra information available (like your Random random = new Random()) example that your eyes need to glide past.

I would wager your brain is more used to scanning your eyes past unnecessary information and can do that with less effort and attention than it can either:

    - bounce back and forth between the chained function calls of the original nested example.
    - synthesize the type and expectations of the intermediate value at any arbitrary point in the piped call chain.
That last thing is the big cost of not naming things. In order to figure out what the value should look like at step 4, you have to work backwards through steps 1-3 again. And you have to do that any time you are debugging, refactoring, unit testing, adding new steps, removing existing steps, etc.

And the work to come up with "obvious" names isn't hard. Start with the easy name:

    batterInPan = pour(batter, pan)
And if the name batterInPan never gets any better and never really helps anyone read or debug or refactor or unit test this code, then in that sense, I guess it's a "waste". I just claim that this case is far less common in the real world and far less costly than having to untangle a mess of unnamed nested or chained call values.

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. 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. It's not ideal, but it's better than every JS library sprinkling a new bit of syntax in just so they can avoid giving their variables names and can use an overloaded modulo operator instead.

Re: Pipe Operator (|>) For JavaScript

#232
post #225

I hope Records & Tuples[0] land before this does. It would have meaningful and far reaching positive effects for the language, without much controversy. Like most of these things, it takes about 5-7 years for it to permeate through enough of the engines to be meaningfully useful in the day to day of web developers (node / deno typically 12-18 months tops). It would drastically speed up existing code once wide adoptio…

I've been wishing for this for years. It opens up whole new ways of doing stuff when tuples and records are just primitives. They never mutate, so representing them efficiently right from the start is possible. They are primitives, so passing should be easier to do. Concurrency becomes a lot easier to add to the language because if you limit it to primitives (which are all immutable), you get a lot of safety guarante…

alot of the class stuff is driven by the vendors. Google & Microsoft tend to be the big champions of the class stuff, like decorators, decorator metadata, the new struct proposal, private fields.

They want classes to be more unique than plain objects (when initially introduced, aside from easy extending via `extend`, they really weren't in practice). You can see it in their frameworks and how they do development. I'm not shocked those proposals get traction quickly because they come from the vendors themselves. I imagine internally their many thousands of engineers take advantage of these features. It just isn't as common (since `class` received a ton of backlash in the JS community mindshare with a broader move to functional style programming)

Records & Tuples on the other hand, came from Bloomberg (largely) and later Meta endorsed it. Unsurprisingly, it solves real problems they face. React (and anything that uses diffing today in the same manner) would be sped up dramatically if they could just `===` two objects vs what they do today. Yet this languishes, despite being a nearly universal upside for the average language user.

Re: Pipe Operator (|>) For JavaScript

#233
post #3

They should have stuck with the F# proposal. The hack proposal just takes one more giant step toward turning JS into Perl. Hack proposal value |> foo(%) for unary function calls, value |> foo(1, %) for n-ary function calls, value |> %.foo() for method calls, value |> % + 1 for arithmetic, value |> [%, 0] for array literals, value |> {foo: %} for object literals, value |> `${%}` for template literals, value |> new Foo…

The F# syntax looks more consistent with idiomatic JS. It always seems there’s some obscure edge case that derails the nice path for these spec proposals though. I haven’t tracked the conversation on this one, but wonder why they didn’t go with it.

Someone at google didn't like it, and apparently that overrode the entire original intent of the proposal. I'm all for industry participation but I was pulling my hair out with this.

Re: Pipe Operator (|>) For JavaScript

#234

I hope Records & Tuples[0] land before this does. It would have meaningful and far reaching positive effects for the language, without much controversy. Like most of these things, it takes about 5-7 years for it to permeate through enough of the engines to be meaningfully useful in the day to day of web developers (node / deno typically 12-18 months tops). It would drastically speed up existing code once wide adoptio…

Is the point of those just immutability or something else too? Wouldn't it be better to have a way to easily make any type deeply immutable? EDIT: I think tuples and records are also supposed to have value semantics, which is great, but why not a mechanism that turns on value semantics for arbitrary object type instead. Also value semantics is separate concept from immutability. Maybe there should have separate ways…

as outlined in the proposal, these new types have engine level guarantees, and support using a plain triple equals (`===`) statement to test structural equality. It also follows that strucural equality trickles down into objects that do this implicitly (Map, Set etc) as well.

Doing this for plain arrays and objects has been said by the vendors for years to be too hard and possibly break alot of existing applications, and a new type for this purpose would need to be proposed. This is an answer to that. There isn't much to be semantically gained by allowing this on frozen objects, you'd need to do something identical to this anyway, from an engine perspective. Using a new syntax / types to represent it semantically makes it easier for developers to understand it too, I'd argue.

Re: Pipe Operator (|>) For JavaScript

#235
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…

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

#236

Earlier quoted context omitted.

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 m…

the refactored version of the example is much worse

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

#237
post #131
post #13

Earlier quoted context omitted.

The JS one does seem to have some more power than the Elixir one. For instance, in Elixir, if it's a bit kludgy to pipe to a second or third argument. I find this often when I want to insert into a map. You can always define more functions, but otherwise it's annoying, because you end up with something like computation() |> &(Map.put(my_map, key, &1)).() That said, with this less-power, you do kind of end up forced t…

As I mentioned upthread, most Elixir functions are designed to have the thing they operate on as first argument. computation() |> &(Map.put(my_map, key, &1)) is terrible style when Map.put(my_map, key, computation()) works just as well and is more readable. It is pretty rare to have a pipeline that needs to insert the value elsewhere than the first position. And please, do not write single element pipelines, I see th…

I agree! I even pointed this out in my comment, but perhaps not clearly :)

I think that the way it's done is a net-positive in designing cleaner APIs, but there are times when I've already done a pipeline, and storing the output is just the last step. This last step is just frustratingly, not always possible. I don't think one should do something like the above, it's just what you must resort to if you _did_ want to do it.

Re: Pipe Operator (|>) For JavaScript

#238

I hope Records & Tuples[0] land before this does. It would have meaningful and far reaching positive effects for the language, without much controversy. Like most of these things, it takes about 5-7 years for it to permeate through enough of the engines to be meaningfully useful in the day to day of web developers (node / deno typically 12-18 months tops). It would drastically speed up existing code once wide adoptio…

Is the point of those just immutability or something else too? Wouldn't it be better to have a way to easily make any type deeply immutable? EDIT: I think tuples and records are also supposed to have value semantics, which is great, but why not a mechanism that turns on value semantics for arbitrary object type instead. Also value semantics is separate concept from immutability. Maybe there should have separate ways…

Objects carry prototypes and mutability with them. Further, all primitives/value types of the language are immutable.

Adding those features to an Object would still necessitate creating a new primitive.

At that point, you might as well make that primitive record that is directly available and just use the constructor to convert (just like you'd use `Number("123")`, you'd use `Record({my: "object"})`).

Re: Pipe Operator (|>) For JavaScript

#239
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…

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 moment(input).utc().format('YYYY-MM-DD HH:mm:ss')
Which apparently you believe should be

    const inputAsMoment = moment(input);
    const inputConvertedToUTC = inputAsMoment.utc()
    return inputConvertedToUTC.format('YYYY-MM-DD HH:mm:ss')

Re: Pipe Operator (|>) For JavaScript

#240

I hope Records & Tuples[0] land before this does. It would have meaningful and far reaching positive effects for the language, without much controversy. Like most of these things, it takes about 5-7 years for it to permeate through enough of the engines to be meaningfully useful in the day to day of web developers (node / deno typically 12-18 months tops). It would drastically speed up existing code once wide adoptio…

The one I really want is “do expressions”. I also can’t understand why anyone wants private fields over these kind of improvements. Lack of private fields in JS has literally never caused a big for me in 15 years of JavaScript development, but I have to use mutable variables and ugly if-else chains to 3 case assignment all the time!
Post reply on HN