Precedence of `=` vs `,`

The precedence below seems inconsistent. In particular, the last result is unexpected. Is the Julia precedence “whatever the parser does”, or is there some underlying design?

julia> quote
       a, b
       end
quote
    #= REPL[92]:2 =#
    (a, b)
end

julia> quote
       (a, b)
       end
quote
    #= REPL[93]:2 =#
    (a, b)
end

julia> quote
       (a=1, b=2)
       end
quote
    #= REPL[94]:2 =#
    (a = 1, b = 2)
end

julia> quote
       a=1, b=2
       end
quote
    #= REPL[94]:2 =#
    a = ((1, b) = 2)
end
3 Likes

If I understand your question correctly, you are wondering why

:((a = 1, b = 2))

returns

:((a = 1, b = 2))

instead of

:(a = (1, b) = 2)

Commas are not listed in the operator precedence table in the manual, but there is a comment in julia-parser.scm that addresses this. The comment says,

comma - higher than assignment outside parentheses, lower when inside

So, since (a = 1, b = 2) has the comma inside parentheses, it has lower precedence than the assignments. On the other hand a = 1, 2 is equivalent to a = (1, 2), because the comma is outside parentheses.

2 Likes

That precedence rule may seem flipflopping for commas but it’s more to do with = meaning keyword arguments in parentheses so you want = to go first.

a = 1, 2 # , first - 1 assignment
a = (1, 2) # () first - 1 assignment

a = 1, b = 2 # , first - fails because (1, b) cannot be assigned to
(a = 1, b = 2) # = first - NamedTuple kwarg
a = 1; b = 2 # 2 assignments

a, b = c, d = 1, 2 # , first - 4 assignments
(a, b = c, d = 1, 2) # = first - failed NamedTuple kwarg at 2

Be careful though, = in parentheses doesn’t always mean it’s a keyword argument, you have to check if it’s in a function call or a NamedTuple construction versus an assignment expression in an operator chain.

julia> identity(v = 1) # identity kwarg
ERROR: MethodError: no method matching identity(; v=1)
...
julia> identity((v = 1)) # identity kwarg, parentheses do nothing
ERROR: MethodError: no method matching identity(; v=1)
...
julia> identity((v = 1,)) # NamedTuple kwarg needs comma
(v = 1,)
julia> identity((v = 1)+0) # assignment in parentheses near binary operator
1
julia> v
1
julia> identity(+(t = 1, 0)) # + kwarg
ERROR: MethodError: no method matching +(::Int64; t=1)
...
julia> identity(+((t = 1), 0)) # + kwarg, parentheses do nothing
ERROR: MethodError: no method matching +(::Int64; t=1)
...