```@.``` throws unexpected error

I get a somewhat odd error with @. MWE:

julia> y = Array{Float64}(undef, 2, 2); @. y =rand(2,2) + ones(2,2)
ERROR: MethodError: Cannot `convert` an object of type Array{Float64,2} to an object of type Float64

Where is the attempted conversion? Moving @. to after the assignment operator works fine, as does pre-allocating the two matrices.

@. affects every function call, which includes ones and rand in your example. The code is equivalent to:

y .= rand.(2, 2) .+ ones.(2, 2)

which roughly means: "for each index in y, do y[I] = rand(2,2) + ones(2, 2)" , which isn’t what you want.

In this case, you may want to just add the . to the functions you actually want to broadcast, as in:

y .= rand(2, 2) .+ ones(2, 2)
2 Likes

Incidentally, when trying to debug code with macros, @macroexpand (or @macroexpand1) is handy.
It probably would have allowed you to find the problem in this case:

julia> @macroexpand @. y = rand(2,2) + ones(2,2)
:(y .= (+).(rand.(2, 2), ones.(2, 2)))

You can also suppress broadcasting with $, as in

@. y = $rand(2,2) + $ones(2,2)

Note that you don’t need to construct an array of ones here. You can just use .+ 1 as in

@. y = $rand(2,2) + 1

In fact, you don’t need to construct the rand(2,2) array either. Just do:

 @. y = rand() + 1

and the rand.() call will call rand() separately for each element of y.

4 Likes

Won’t the last one be slower than the previous? As I understood it, we have optimizations for generating multiple random numbers at once.

Allocating a 2x2 temporary array just to discard it is also slow; it’s a tradeoff. In general, I would err on the side of fewer temporary arrays and more readable code.

3 Likes