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(%) for constructing objects,
value |> await % for awaiting promises,
value |> (yield %) for yielding generator values,
value |> import(%) for calling function-like keywords,
F# proposal
value |> x=> x.foo() for method calls,
value |> x=> x + 1 for arithmetic,
value |> x=> [x, 0] for array literals,
value |> x=> ({foo: x}) for object literals,
value |> x=> `${x}` for template literals,
value |> x=> new Foo(x) for constructing objects,
value |> x=> import(x) for calling function-like keywords,
F# proposal would make `await` and `yield` into special syntax cases or not allowed.
I'd rather do await/yield the old fashioned way (or slightly complicate the already complex JS syntax rules) than add the weird extra syntax. Arrow functions are elegant and already well-known and well-understood.
The proposal is not finished yet (and might never been). Pessimism aside, there is a whole issue on why it was decided on following up with Hack's implementation [1].
You can always give your input on such decisions, the % token is still being "bikeshedded"[2] (is that a word?), and there's still a possibility of making follow-ups proposals that could implement some F#-esque implementation
On the one hand, I tend to agree and I dislike making JS syntax even more complex than it already is.
On the other hand, it works well in F# (and the ML that then borrowed it from F#) because it’s just a standard infix operator there and everything is already curried which is definitely not the case with JS. It means you will nearly always have to use a lambda when piping in JS which is honestly a bit tedious.
I really enjoy writing me some of that F#, esp. with Bolero, but I would take `value |> foo(%)` over actual F#'s `value |> (fun x -> foo x)` any day. However, I agree that the "F# proposal" comes across as better, esp. when we consider -copypasting- consistency of the language. Now, considering everything in JS already, you are right, we did it again, didn't we? After couple more years, the Perl and Javascript languages will finally merge and become one.
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.
I also pushed for this in TC39 which was shut down for seemingly no reason. Since only one language with almost no user base uses |> to mean expressions, people are guaranteed to get the wrong idea about how it works. It almost seems like intentional misleading.
It's more common for pattern matching Java's new syntax, Erlang, Elixir, StandardML (fat arrow), F#, Kotlin, Ocaml, Haskell, Rust (fat arrow), Ada (fat arrow), Scala (fat arrow), Zig (fat arrow), and probably a bunch of others too.
That's a lot of prior art for people to be comfortable with and as the fat arrow already has another meaning, overloading it in pattern matching might complicate things.
Right but then it would not be the same as in those other languages which use fat arrow anyway.
Another syntax for pattern-matching could be simply ':' instead of the arrow.
In the early days of Smalltalk the Smalltalk return statement was simply '^'. That could also be suitable for pattern matching. The idea would be that the switch statement returns something meaning pushing it up from the expression to whoever called it. So '^' might be good for that. Whereas pushing the results to the right to the next expression could be ->.
I originally thought you were referring to this as a "hack proposal" as a way of denigrating its value, but in fact it is the "Hack proposal" where "Hack" is Facebook's fork of PHP.
Is either proposal compatible with later adding a backward pipe <| operator?
If so I think that should be a consideration, even if in practice there isn't massive value in a backward pipe operator in javascript. It would be a shame to later want to add it and have to add another layer of kludge and messy syntax.
Yeah, F# has a backward pipe operator, and it works like this:
a_value |> (fun a b -> a + b) <| b_value
In F#, this works because of automatic function currying. Not sure how that would apply to Javascript, though. Without function currying, what would this even mean?
a_value |> ((a, b) => a + b) <| b_value
...since there's no currying, you'd just immediately invoke the function that sits "in the middle" with `a` set to `a_value`, but `b` set to `undefined`.
The Hack-style proposal though...I don't think it would work with a backward-pipe operator at all. Not without adding a _second_ special-case symbol, at least.
For the non initiated amongst us who might be confused, F# has first class functions and everything is curried.
The expression you see is evaluated left-to-right. (|>) is a function taking a_value and (fun a b -> a+b) as arguments and applying a_value to the function. This returns a function taking b as an argument (that’s called a partial application). (<|) is once again a function taking the resulting function and b_value as arguments and applying b_value to its first argument which finally returns the wanted results.
The issue with unary function doesn't exist in F# because every functions can be seen as a unary function returning a function taking one less argument thanks to partial application. That's the beauty of currying.
This proposal reminds me of Scala with anonymous parameters '_'. Could I use more than one '%' for curried functions. xs.reduce(_+_)? Though I guess for perf reasons it might make sense to keep things as tuples so it would be xs.reduce(%[0]+%[1]).
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.
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.
Hack proposal
F# proposal F# proposal would make `await` and `yield` into special syntax cases or not allowed.I'd rather do await/yield the old fashioned way (or slightly complicate the already complex JS syntax rules) than add the weird extra syntax. Arrow functions are elegant and already well-known and well-understood.