Inconsistent behavior with double indexing?

Consider objects a and b, which are array of arrays defined below. These objects are equal according to Julia and the only difference is in how I create them. But double-indexing works very differently on each.

julia> a=fill([3,4],2)
2-element Array{Array{Int64,1},1}:
 [3, 4]
 [3, 4]

julia> b=[[3,4],[3,4]]
2-element Array{Array{Int64,1},1}:
 [3, 4]
 [3, 4]

julia> a==b
true

julia> a[1][1]=5
5

julia> a
2-element Array{Array{Int64,1},1}:
 [5, 4]
 [5, 4]

julia> b[1][1]=5
5

julia> b
2-element Array{Array{Int64,1},1}:
 [5, 4]
 [3, 4]

Can anyone explain (1) why a and b behave differently or (2) how I can modify my code to have it always behave like b, which seems like the intuitively correct result?

The issue is not with indexing but at the creation of a : when you use fill([3,4],2), both elements of a point to the same object in memory (here a vector of value [3,4]). You can check that a[1]===a[2] (note the triple = ) whereas b[1] !=== b[2]. Which means that modifying this object will be reflected in all its occurrences.

EDIT : You can completely change a[1] with a[1]=[5,4] (it will not mutate the old a[1] but create a new element that is not linked to “old” a[1] and a[2] (that will be preserved). But I’m not sure it is easy to do otherwise.

Thanks for explaining why this is happening.

My overall goal was to create an array with placeholder NaN values using fill, then use a for loop to replace each entry. This would need a fill function that creates copies instead of references (I’m not sure how to accomplish this but it may involve the deepcopy function).

Some other things that might work: adding one dimension to the array instead of using an array of arrays (this only works if the sizes are consistent), or push!-ing each new array to build up an array over iterations. These are probably better solutions anyway.

An array comprehension is often a nice way to do this: [[3,4] for _ in 1:2].

See also the somehow related old discussion here …