Help understanding broadcasted pipe operator

I would expect the result of

[1, 2] .|> u->u^2 |> sum

to give the answer 5 since

[1, 2] .|> u->u^2

gives

2-element Array{Int64,1}:
 1
 4

and

[1, 4] |> sum

gives 5.

Instead I am getting

[1, 2] .|> u->u^2 |> sum

2-element Array{Int64,1}:
 1
 4

What’s going on here? It seems like the second pipe is broadcasting over the vector even though I am not using the dot pipe operator.

What’s weird is I can call them separately in the REPL and it works the way I expect it to:

julia> [1, 2] .|> u->u^2
2-element Array{Int64,1}:
 1
 4

julia> ans |> sum
5
1 Like
julia> ([1, 2] .|> u->u^2) |> sum
5

Can’t explain why though

I think it gets parsed as [1, 2] .|> (u->u^2) |> sum)

julia> Meta.lower(Main,:([1, 2] .|> u->u^2 |> sum))
 # ...
│   %2  = (Core.svec)(##10#11, Core.Any)
│   %3  = (Core.svec)()
│   %4  = (Core.svec)(%2, %3)
#...
    (%1)()
    (Base.literal_pow)(^, u, %2)
    %3 |> sum
    return %4
end)))
#...
2 Likes

Even simpler than Meta.lower, you can just see it by quoting it:

julia> :([1, 2] .|> u->u^2 |> sum)
:([1, 2] .|> (u->begin
              #= REPL[2]:1 =#
              u ^ 2 |> sum
          end))

This is how it works without broadcasting, too:

julia> :([1, 2] |> u->u^2 |> sum)
:([1, 2] |> (u->begin
              #= REPL[3]:1 =#
              u ^ 2 |> sum
          end))

The trick is that the last |> is becoming a part of the anonymous function! Here’s another fix:

julia> [1, 2] .|> (u->u^2) |> sum
5
8 Likes

Oh, that makes sense. Thanks!