Live data from Hacker News

Pipe Operator (|>) For JavaScript

github.com

271–280 of 437 posts

Re: Pipe Operator (|>) For JavaScript

#271
I *HATE* pipes. For example from Elixir School (https://elixirschool.com/en/lessons/basics/pipe_operator):

``` foo(bar(baz(new_function(other_function())))) ```

They offer this example of an improvement:

``` other_function() |> new_function() |> baz() |> bar() |> foo() ```

While yes, pipes improve readability, how do they deal with errors? How do they deal with understanding what each thing is supposed to return?

I would prefer something like this, (descriptive variable names):

``` var userData = other_function();

var userDetails = new_function(userData);

var userComments = baz(userDetails);

var userPosts = bar(userComments);

var finalUserDetails = foo(userPosts);

return finalUserDetails; ```

Then I can easily debug each step, I can easily understand what each call is supposed to do, if I'm using type script, I can assign types to each variable.

I strongly oppose clean code for the sake of looking pretty, or being quick to type. Code is meant to be run and read more then written, it should be descriptive, it should describe what it's doing not a nasty chain of gibberish. Hence why most people hate REGEX.

Re: Pipe Operator (|>) For JavaScript

#272
post #257
post #229

Earlier quoted context omitted.

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".

What is the point then?

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

#273

I * HATE* pipes. For example from Elixir School ( https://elixirschool.com/en/lessons/basics/pipe_operator ): ``` foo(bar(baz(new_function(other_function())))) ``` They offer this example of an improvement: ``` other_function() |> new_function() |> baz() |> bar() |> foo() ``` While yes, pipes improve readability, how do they deal with errors? How do they deal with understanding what each thing is supposed to return?…

I think there is merit to the argument that if naming is one of the hard problems, programmers writing that code are having to do a lot of ‘naming’ and that is hard for them. The proposed pipe operation eliminates those names and lets the programmer just use %.

But these variables are rarely the kind of thing it’s hard to name, so it feels like a slightly disingenuous argument.

Re: Pipe Operator (|>) For JavaScript

#274
post #258
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…

Consider the example code here in Hack, const weather = `https://api.weather.gov/gridpoints/TOP/31,80/forecast` |> await fetch(%) |> await %.json() |> %.properties.periods[0] In F# it would be much more verbose, const weather = `https://api.weather.gov/gridpoints/TOP/31,80/forecast` |> fetch |> await |> json |> await |> x => x.properties.periods[0] // or |> { properties : { periods: [result] } } => result Hack will a…

Your example is bad. Fetch resolves the promise even if you get a 400 or 500 error.

If your project is going to be robust, you MUST intercept the result and check before asking for JSON.

    const resp = fetch(`https://api.weather.gov/gridpoints/TOP/31,80/forecast`)
    if (resp.ok) {
      const weather = await resp.json()
        |> x => x.properties.periods[0]
    } else {
      ...
    }
Your hack-syntax response would then become

    const resp = fetch(`https://api.weather.gov/gridpoints/TOP/31,80/forecast`)
    if (resp.ok) {
      const weather = await resp.json()
        |> %.properties.periods[0]
    } else {
      ...
    }
Hardly a big win and not at all a win when you realize that you can't copy/past code to and from that syntax without risking weird errors due to the special symbol.

`await` isn't a function and (as I noted) either wouldn't be possible or would require special syntactic consideration for F# syntax, but the hack syntax is basically one giant ball of special syntactic considerations.

I'd rather explicit async/await and keep the simplicity of the F# syntax.

Re: Pipe Operator (|>) For JavaScript

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

Wouldn't it be better to use '->' as the operator? This is about dataflow so an arrow would represent that nicely. Whereas '|>' doesn't really "mean" anything. An arrow means that something flows in the direction of the arrow.

Sure, but I'd rather reserve that for a pattern-matching switch statement.

Re: Pipe Operator (|>) For JavaScript

#276
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 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

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

SELECT 'Jerk' FROM jerkings_tab;

Is this Perl?

DROP jerkings_tab;

Is this really Perl?

Re: Pipe Operator (|>) For JavaScript

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

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

#280
post #237
post #131

Earlier quoted context omitted.

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…

There is nothing wrong with doing

   data =
     this
     |> is
     |> a
     |> pipeline

   save_to_file(file, data)
Instead of trying to put the call to save_to_file into the pipeline by wrapping it in a closure.
Post reply on HN