Another day, another proposal for a JS language feature that optimizes for fewest possible characters as though fewer characters means “more readable” (perl and haskell show this to be false), or more understandable.
The proposal is an entire language feature and syntax to support a single construct:
Which is frankly not anything remotely common enough to warrant a custom syntax.
Their argument against this is that it is hard to read if the nesting is too deep, and the temporaries are unclear, especially if reused. Which is an absurd argument, because why would you be reusing a single temporary, unless again you believe in optimizing for fewest characters written, as if that were the core metric for productivity.
The proposal attempts to justify this by saying the proposal applies to other cases:
By reusing the % operator as an unnamed token is more readable:
c() |> b(%, c() |> d
Which is is more characters (gasp!) and I would say much less readable, but also is half assed: which function should get to be %?
The anchor also has orthogonality problems:
a |> (c |> f(%)) |> d
The obvious response here is “don’t do that, it’s unreadable”, but that fails to acknowledge that the only reason this occurs is this new syntax being insufficiently thought through. Again, that’s because fundamentally the proposal owners only care about their a(b(c(d()))) case, and try to paper over this with the pretense of covering other cases.
I tend to agree. In using JQuery I’ve found this method-concatenation style very convenient & readable. But adding a new operator and a new placeholder token to the language, just to make this style work with non-methods, seems like overkill. (I find the “F# style” much cleaner, but for whatever reason it’s already been rejected…)
Anyway, I’m glad I mostly use languages that support operator overloading, so I’m not dependent on some capricious language committee to create new operators :-p
I feel arbitrary custom operators are a hindrance to understanding code. A plain text function name can be read and understood by someone unfamiliar with the code, but if you use a random operator/sigil a person lacking codebase familiarity cannot just read code, they have to seek out and find the definitions for each operator.
Personally I don’t think that the character savings for custom operators warrant the complexity increase. I’m aware that some code can “read” better purely left-to-right (another factitious argument from the earlier paper that “normal” code is left-to-right), but I am not convinced custom infix operators are worth it, but some languages. - say Haskell - allow infixed named operators.
const res_a = a(value)
const res_b = b(res_a)
and so on, do mainline JS interpreters not optimise that out with constant folding or whatever?
I’m not sure what you’re asking, there’s nothing to constant fold there
Don’t worry, I’m not quite sure what I was asking either.
I realize you may have been confused by their obsession with temporaries being bad. What’s happening there is that the authors are actually wanting to measure efficiency of code by number of characters. Of course they can’t say that because it’s an objectively false measure of efficiency and legibility, so they come up with a bunch of bogus insinuations about performance.
For a modern JS engine there is no performance difference between
let htemp = h(a)
let gtemp = g(htemp)
or the hypothetical
a |> h |> g |> f
Unless there is an eval() in the scope (but no one uses eval right? :D), a closure containing an eval(), or a closure referencing htemp or gtemp, but of course if you wanted to do that then the local var has to exist regardless.
Without currying, piping kinda sucks. None of the stdlib stuff would do well supporting either. Do you want [ 1, 2 ] |> Array.prototype.map.call(x => x + 1)? This only works if unexpectedly |> pipes to the first argument cough Elixir. If you are the type of person that wants a pipe operator you’re probably leaning functional in style and you’ll almost certainly be happier with compile-to-JS languages that support it at a more fundamentally level; there are dozens to choose from.
[ 1, 2 ] |> Array.prototype.map.call(x => x + 1)
The problem w.r.t to currying is that you cannot add currying to JS, as all functions can be call under or over applied. Currying requires at minimum arity level typing of functions, and you just can’t make JS work with that - there’s no way a call site can know whether it’s a curried vs. non curried call.
As they are:
a = d(c(b,7))
The current proposal:
a = b|>c(%,7)|>d(%)
I would prefer this:
a = b,7~>c~>d