The pipe operator in Elixir also benefits from having the subject of most functions in the standard library as first argument. No need for the % hack operator, so you can just do:
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 to design your functions in a way to where piping makes sense, and IMO it leads to cleaner and more consistent APIs.
Pipes work really well with named arguments and partial-application. Both functionalities make it easy to get the unary function you want with minimal cruft. Lambdas solve the more complex case.
In Ocaml, you often end up doing things like:
List.create 0 3
|> List.map ~f:(fun x -> x+1)
|> List.fold ~init:0 ~f:(fun acc x -> x+acc)
|> Stdio.print_endline "%d"
I'm ambivalent about adding them to JS however. It's a nice feature but I don't think it works well with the rest of the syntax.
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 them far too often from Elixir beginners.
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.
That's probably a wise choice. Pipes are great for simple situations, mostly for code clarity. But it can be abused easily, like a hammer seeking nails.
It's similar to await/async, you eventually start designing code that better suits that interface rather than pigeonholing it with complex syntax.
Oh wow, TIL about `Kernel.then/2`. That definitely works around the syntax problem.
An aside, the implementation is kind of amusing. It almost seems unnecessary for this to be a macro but maybe the compiler can optimize this a bit more? I would expect TCO to simplify of my "simple" implementation of
It's nice in Elixir because there's a strong convention that the first argument is where you'd almost always pipe into. The JS proposal is better for retrofitting in a language.
This isn't the pipe operator in elixir. It's from some php derivative language that facebook uses and you shouldn't trust it, because nobody could even show in TC39 that it was sound.