Initializing Array of Arrays with undef gives UndefRefError?

Hi all,

I am initializing an Array of Arrays with undef. Why does it give me an UndefRefError when accessing it, whereas an Array with undef does not? Also, did some behavior change? I seem to remember initializing Array of Arrays before and never having a UndefRefError before.

a = Array{Int64}(undef, 10)
b = Array{Array{Int64}}(undef, 10)

a[1] # No error
b[1] # UndefRefError

PS: performance issues or best practices asides. It seems that using fill to initialize Array of Arrays might be better, but I’m just wondering what’s happening in the above case.

When you use Vector{T}(undef, n), the uninitialized elements of the vector will be filled with random data (whatever happens to be in memory) if T is an isbits type. If T is not an isbits type, then you will get an UndefRefError if you try to access an uninitialized element, since the element hasn’t been initialized with a pointer to an instance of the non-isbits type.

julia> isbitstype(Int)
true

julia> Vector{Int}(undef, 1)
1-element Array{Int64,1}:
 4588932080

julia> isbitstype(String)
false

julia> Vector{String}(undef, 1)
1-element Array{String,1}:
 #undef

julia> struct A
           x::Int
       end

julia> isbitstype(A)
true

julia> Vector{A}(undef, 1)
1-element Array{A,1}:
 A(4438511664)

julia> mutable struct B
           x::Int
       end

julia> isbitstype(B)
false

julia> Vector{B}(undef, 1)
1-element Array{B,1}:
 #undef
4 Likes

It seems that using fill to initialize Array of Arrays might be better

Watch out for the potential pitfall. See the example in Arrays · The Julia Language

1 Like

As @Paul_Soderlind mentioned, fill is probably not the right tool, unless you want every field to have the same vector. An alternative is using a list comprehension:

b = [Vector{Int64}() for _ = 1:10]

But there is nothing wrong with creating a uninitialized Vector and then assign a inner Vector to each position before accessing it.

2 Likes