Is * a ternary/quarternary operator in 1.7+, or am I missing something that was there before?

So I noticed this bit in matmul.jl

# Three-argument *
"""
    *(A, B::AbstractMatrix, C)
    A * B * C * D
Chained multiplication of 3 or 4 matrices is done in the most efficient sequence,
based on the sizes of the arrays. That is, the number of scalar multiplications needed
for `(A * B) * C` (with 3 dense matrices) is compared to that for `A * (B * C)`
to choose which of these to execute.

Which implies that a chain of * is not parsed as a sequence of binary operations. I was not aware of this, and looks like it works for any length chain.

julia> module MyMul
         *(x,y,z) = 3
         *(x,y,z,a,b,c) = 6
         function test()
           println(1*2*3)
           println(1*2*3*4*5*6)
           println(1*2*3*4)
         end
       end
Main.MyMul

julia> MyMul.test()
3
6
ERROR: MethodError: no method matching *(::Int64, ::Int64, ::Int64, ::Int64)
You may have intended to import Base.:*

Is this a v1.7 parser change, or is this something else? What other operators can I expect to act like this?

julia> module MyMul
         import Base.:*
         *(x,y,z) = 3
         *(x,y,z,a,b,c) = 6
         function test()
           println(1*2*3)
           println(1*2*3*4*5*6)
           println(1*2*3*4)
         end
       end
Main.MyMul

julia> MyMul.test()
3
6
24

I believe the only other such operators are + and ++. And that the parsing has worked this way forever, certainly on 1.0:

julia> :(1*2*3) |> dump
Expr
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol *
    2: Int64 1
    3: Int64 2
    4: Int64 3

julia> :(1+2+3)
:(1 + 2 + 3)

julia> :(1++2++3)
:(1 ++ 2 ++ 3)

julia> :(1/2/3)
:((1 / 2) / 3)

julia> VERSION
v"1.0.5"

For + and *, there are fallback definitions which work left-to-right, e.g. @less 1 * 2 * 3. What is new on 1.7 is that some chains of matrix multiplication will be done in other orders if this is more efficient. (Before this, there were also some other specialisations such as @which [1,2]' * Diagonal([3,4]) * [5,6].)

1 Like

Exactly that, for the operator + and * this is stated in the documentation here. But it also works like that for ++ too.

2 Likes

I intentionally avoided modifying Base.:*, I didn’t want anyone to run that example and have to restart their session afterward.