Error with @views and a function

I’m getting this strange error when trying to use views with a function. Here is a MWE:

x = Array{Float64}(undef, 3, 3, 3)
y = similar(x)

@views function fun(x, y, t)
    y[:, :, t], x[:, :, t] = rand(3, 3)
    return nothing
end

When I try to define fun I get the error

ERROR: syntax: function argument name not unique: ":" around REPL[3]:2
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

Why does that happen?

First we have to address that without the @view macro, that code would cause another error:

julia> fun(x, y, 1)
ERROR: ArgumentError: indexed assignment with a single value to possibly many locations is not supported; perhaps use broadcasting `.=` instead?

y[:, :, t], x[:, :, t] = rand(3, 3) is a problem, you can’t assign to multiple destinations in one line. @views does not account for this, and it blindly transformed the error-throwing code to something that throws another error. You can check @macroexpand to see what it does:

julia> @macroexpand @views function fun(x, y, t)
           y[:, :, t], x[:, :, t] = rand(3, 3)
           return nothing
       end
:(function fun(x, y, t)
      #= REPL[4]:1 =#
      #= REPL[4]:2 =#
      ((Base.maybeview)(y, :, :, t), (Base.maybeview)(x, :, :, t)) = rand(3, 3)
      #= REPL[4]:3 =#
      return nothing
  end)

The parser mistakes that as a method definition, one with 2 identical arguments :.

This fix works fine, but @views seems unnecessary:

@views function fun(x, y, t)
  result = rand(3,3)
  y[:, :, t] = result
  x[:, :, t] = result
  return nothing
end
1 Like

Oh, that multiple assignments was a mistake copying the example here.
In my application the assignment is something like

y[:, :, t], x[:, :, t] = otherfun(...)

where otherfun returns two different arrays that are conformable with x[:, :, t] and y[:, :, t].
I read somewhere a long time ago that @views can save some time because slicing arrays create temporary copies but views do not. Is that still a valid point?

Yeah that should work without error. Still, @views doesn’t transform it properly because it assumes single assignment.

That’s true, but you don’t allocate here to begin with because the slicing is on the left side of the assignment. Allocations happen on the right side, which includes expressions like A[i] += B because that just lowers to A[i] = A[i] + B.

1 Like