# Pipe operator quiz! Can you guess the result?

Question 1

``````A=[1,2,3];
B=[1,1,1];

A.>B |> sum
``````

Question 2

``````1:2 .|> x->x^2 |> sum |> inv
``````

Question 3 (warning: spoilers)

The behaviors above seem just… evil! . Can we fix this? Changing the operator precedence is breaking, but is there really code out there relying on this behavior?

Credits: First example from personal suffering. Second example adapted from this discussion, itself adapted from the documentation:

``````help?> |>
search: |>

|>(x, f)

Applies a function to the preceding argument. This allows for easy function chaining.

Examples
≡≡≡≡≡≡≡≡≡≡

julia> [1:5;] |> x->x.^2 |> sum |> inv
0.01818181818181818
``````
3 Likes

For any programming language, learn the 5 most obvious precedence rules (maybe in Julia `+ -`, `*`, `&& ||`), and use parentheses for everything else. Otherwise you get bugs like this, as

``````julia> Meta.show_sexpr(:(A.>B |> sum))
(:call, :.>, :A, (:call, :|>, :B, :sum))
``````
6 Likes

The problem is people tend to use the pipe for multi-line operations where visually it’s less obvious to them that they would need to do that. Like:

``````(1, 2)   .|>
x -> x^2  |>
sum
``````

I mean, I agree that its always best to use parentheses when things are ambiguous, but I’ve seen similar code as the above so many times in the wild that I don’t think it’s even in people’s mind that this could be interpreted the way it is.

2 Likes

@Tamas_Papp I don’t think this rule of thumb really works in practice. At least you probably want to add `[]`, `.`, `^`, `//` and `=`, probably a few others. Nobody wants to write

``````(obj.field) = ((A[3]) // (x^2))
``````

``````obj.field = A[3] // x^2
``````

I agree in spirit: it’s best to use parentheses than rely on non-obvious precedences that few people know by heart (for example when using bitwise operators).

But the problem here is not the ambiguity, it’s that Julia’s behavior is counter-intuitive. In the examples above, it’s almost obvious what the precedence “should” be, so users won’t expect parentheses to be necessary.

I think it’s especially bad with the `|>` operator: as @jonniedie says it’s used to write computation steps line-by-line, so users really don’t expect they have to add parentheses there.

Another reason I find the high precedence of `|>` annoying: this operator provides a nice way to build complex computations incrementally in the REPL (only for quick operations obviously). It’s a habit I took from working in Unix shells. It looks like this:

``````# look at some values in the REPL
sin.(0:.1:pi)

# add some filter (get previous command with Ctrl-p)
sin.(0:.1:pi) |> x->filter(>(0.5), x)

# that was bad, let's fix it (get previous command with Ctrl-p)
sin.(0:.1:pi) |> x->filter(>(0.4), x)

# OK now let's finish (get previous command with Ctrl-p)
sin.(0:.1:pi) |> x->filter(>(0.4), x) |> sum
``````

At the end of the process I have a nice one-liner I can save or share with someone. But it’s much less convenient if after `Ctrl-p` I have to move around to add parentheses…

Possibly. People have very heterogeneous intuition about operators that are not common in math and/or language-specific. I don’t feel very strongly about this either way, but since it is a breaking change, I imagine that very good reasons would be requied to change this. The best way forward is probably opening an issue.

Generally, with Unicode, Julia allows a very large number of operators with new ones addes all the time, so relying on intuition for precedence is a bit shaky — “intuition for operator precedence” is something people disagree about all the time. One can classify operators to various classes (eg “like +”) as the parser does, but that again is not intuitive for all operators.

Which is why I suggest parenthesizing almost everything nontrivial. Yes, I agree that it is somewhat inconvenient, but I think it has payoffs.

3 Likes

Similar things in R:

``````library(magrittr)
> A = c(1,2,3); B = c(1, 1, 1)
> A > B %>% sum
[1] FALSE FALSE FALSE
> 1:2 %>% function(x)x^2 %>% sum
Error: Anonymous functions myst be parenthesized
> 1:2 %>% (function(x)x^2) %>% sum
[1] 5
``````

For Question 1, R behaves the same as julia.
To add something to Tamas, I think the “intuition” can also depends on the context. For example, `==` and `>` should have similar precedence, and what should be the “intuition” for this one?

`````` sin.(1:3) .== 1:3 .|> sin
``````

For Question 2, R can give the error message when it is “ambiguous” because `%>%` uses “non-standard evaluation” which is similar to macro in julia. Maybe a similar idea can also be tested in various julia pipe packages?
And I think it is really a good practice to parenthesize anonymous functions, except in very simple cases.

2 Likes