Weird behavior assigning values to initialized vector of matrices?

I came across a behavior of arrays of arrays that I find unintuitive. I suspect I might be missing something basic here.

I think the following illustrates the behavior. Suppose I make a vector of matrices

julia> V = Vector{Matrix{Float64}}(undef, 2)
2-element Vector{Matrix{Float64}}:
 #undef
 #undef

and I would like to initialize each component of this vector to have size 2\times 2, say

julia> fill!(V, Matrix{Float64}(undef, 2, 2));

Then, I’d like to set the upper left element of the matrix in V[1] to be 42.0:

julia> V[1][1,1] = 42.0;

I find that it works, but it also sets the upper left element of the matrix in V[2] to 42.0

julia> V[1]
2×2 Matrix{Float64}:
 42.0           1.36587e-314
  1.36587e-314  5.84085e-315

julia> V[2]
2×2 Matrix{Float64}:
 42.0           1.36587e-314
  1.36587e-314  5.84085e-315

Is there a way to assign values to the elements of these matrices independently? Is there an explanation for this behavior?

This is basically the same as the recent thread: Current behavior of fill and the like..?

The explanation of this behavior is already included in the documentation of fill!:

help?> fill!
search: fill! fill finally findall

fill!(A, x)

Fill array A with the value x. If x is an object reference, all elements will refer to the same object. fill!(A, Foo()) will return A filled with the result of evaluating Foo() once.

If you want to initialize something creating multiple distinct objects instead of using always the same, either use an array comprehension or map(copy, ...) as it is suggested in that thread. In your specific case, as the container already exist, maybe the best solution is V .= copy.(value).

2 Likes