Semantically equivalent expressions with wildly different performance

Yeah it basically ran faster because it didn’t do anything:

julia> outer1!(copy(M), x, y) ≈ M
true

julia> M ≈ outer2!(copy(M), x, y)
false

Looks like @. failure causing a method expression. This example of overlapping syntax causing a silent error probably counts as a WAT, so I suggest adding a wat tag for future discoverability.

julia> @macroexpand @. (view(output, :, j)) = x *  y[j]
:(view(output, :, j) = begin
          #= REPL[51]:1 =#
          (*).(x, y[j])
      end)

julia> let
       view(output, :, j) = begin
               #= REPL[51]:1 =#
               (*).(x, y[j])
           end
       end
(::var"#view#3") (generic function with 1 method)

julia> @macroexpand @. (v) = x *  y[j]
:(v .= (*).(x, y[j]))

julia> @macroexpand (view(output, :, j)) .= x .*  y[j] # manual fix
:(view(output, :, j) .= x .* y[j])

A fix after which:

julia> outer1!(copy(M), x, y) ≈ outer2!(copy(M), x, y)
true

julia> @btime outer1!($(copy(M)), $x, $y);
  248.700 μs (0 allocations: 0 bytes)

julia> @btime outer2!($(copy(M)), $x, $y);
  249.000 μs (0 allocations: 0 bytes)

Benchmarks that mutate their inputs are generally bad but this might be fine for runtime because there are no conditionals.

2 Likes