In most uses of functional-style piping I’ve seen in Julia, it seems that a lot of people don’t realize that
|> has precedence over
x -> f(x) |>
x -> g(f(x))
(x -> f(x)) |>
In most cases, it doesn’t really matter because it works out the same either way, but it can do some unexpected things with broadcasted piping:
julia> (1, 2) .|>
x -> x^2 |>
julia> (1, 2) .|>
(x -> x^2) |>
I bring this up because I see this mistake everywhere. I’ve seen it on questions posted here. I’ve seen it in blog posts from pretty experienced data scientists. I even saw it in a tutorial this morning.
This seems like one of those “if everyone is walking over the same path on a lawn, maybe we should pave a walkway over that path” situations. I can only see this type of usage increasing as functional programming styles are becoming more popular. Of course, it could be mentioned in up front the docs that it is a good practice to use parentheses in this case to avoid ambiguity, but there are only so many things we can put up front in the docs.
If you do
?|> the example is potentially a source of problem:
Applies a function to the preceding argument. This allows for easy function
julia> [1:5;] |> x->x.^2 |> sum |> inv
Maybe just adding parentheses there would help… adding another example with broadcasted piping along the lines that you suggested could be nice too. Like
julia> (1, 2) .|> (x -> x^2) |> sum
That could be a nice little PR?
Oh, that’s interesting. I hadn’t noticed it there. That PR would certainly help, but I also think this is the type of thing that people tend to use without looking at the help docstring because it seems so self-explanatory.
but wouldn’t you say that people who’ve never seen that operator before might try to do
?|> it seems the easiest way to find info (e.g. you might not even know what to look for, that it’s called “pipe” or whatever).
Anyway I just think if you opened a PR, it would be very welcome; changing precedence would be for Julia 2.0 anyway (and I’m also not convinced it’s a good idea but I’m not very opinionated on the matter).
That’s a good point. Either way, it’s probably the right thing to do, so I’ll open one up later today.
As far as the precedence goes, I would be curious to see cases where changing it breaks code that shouldn’t already be erroring. Or in other words, the code that would break from this change might have been computing something unexpected before since I doubt many people are using something like
(1, 2) .|> x -> x^2 |> sum to purposely mean
(1, 2) .|> x -> (x^2 |> sum).