Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Fast pipe precedence #2174
I think these should always mean exactly the same thing:
This is a really confusing experience and is especially awkward when upgrading the relatively pretty:
to the paren heavy:
Apologies if this is a KP or already open somewhere. It's a little tricky to search for operators and I didn't see anything.
One of the goals of the fast pipe sugar is to allow certain kinds of code that isn't possible with the infix operator
/* before with infix operator |. */ (location |. streets) /* after with fast pipe sugar */ location->streets
To allow easy stubbing of
a->f(b); /* ast sees */ (a->f)(b); (a |. f)(b); /* ocaml executes, because of let (|.) = (a, f) => f(a) */ f(a)(b);
The downside is that we get the following transformation:
foo |. Map.get("bar") |. Option.getWithDefault("baz"); /* precedence of |. results in the following ast */ foo |. (Map.get("bar")) |. (Option.getWithDefault("baz")); /* refmt prints */ foo ->(Map.get("bar")) ->(Option.getWithDefault("baz"));
With the precedence of fast pipe and the fact that it doesn't accept an expression with function application on the right side, the parens are necessary. Also note the ast stays the same here.
foo ->Map.get("bar") ->Option.getWithDefault("baz"); (((foo->Map.get)("bar"))->Option.getWithDefault)("baz"); (((foo |. Map.get)("bar")) |. Option.getWithDefault)("baz");
Refmt should not change the meaning of your program's ast, hence we print the parens to conserve the original ast…
@rickyvetter does this make sense? Do you have a suggestion on how we could solve this?
Yup. This makes a lot of sense! Thanks for going through the detailed explanation (for the nth time!).
If I understand correctly, the place where meaning differs is when the pipe has a another operator on the right hand side that isn't some form of function application. So