1
votes

I want to generate a Dict with undef values so I can later loop over the keys and fill in correct values. I can initialise an such a Dict using concrete types in the following way and it all works fine:

currencies = ["USD", "AUD", "GBP"]
struct example
    num::Float64
end
undef_array =  Array{example}(undef,3)
Dict{String,example}(zip(currencies, undef_array))

When my struct has an abstract type however I can still generate the undef array but I cannot create the dict. I get an error "UndefRefError: access to undefined reference"

abstract type abstract_num end
struct example2
    num::abstract_num
end
undef_array =  Array{example2}(undef,3)
Dict{String,example2}(zip(currencies, undef_array))

Although it is possible to create such a Dict with a concrete array:

struct numnum <: abstract_num
    num::Float64
end
def_array = [example2(numnum(5.0)), example2(numnum(6.0)), example2(numnum(4.5))]
Dict{String,example2}(zip(currencies, def_array))

Question

My question is whether it is possible to generate a Dict with undef values of a type that relies on an abstract type? Is it is possible what is the best way to do it?

2

2 Answers

3
votes

In your second (not working) example, undef_array is an array whos elements aren't initialized:

julia> undef_array =  Array{example2}(undef,3)
3-element Array{example2,1}:
 #undef
 #undef
 #undef

The reason is that it's not possible to instantiate an object of type example2 because your abstract type abstract_num (the type of the field of example2) doesn't have any concrete subtypes and, thus, can't be instantiated either. As a consequence even indexing undef_array[1] gives an UndefRefError and, hence, also zip won't work.

Compare this to the first case where the array elements are (arbitrarily) initialized:

julia> undef_array =  Array{example}(undef,3)
3-element Array{example,1}:
 example(1.17014136e-315)
 example(1.17014144e-315)
 example(1.17014152e-315)

and undef_array[1] works just fine.

Having said that, I'm not really sure what you try to achieve here. Why not just create a mydict = Dict{String, example2}() and fill it with content when the time comes? (As said above, you would have to define concrete subtypes of abstract_num first)

For performance reasons you should, in general, avoid creating types with fields of an abstract type.

1
votes

Try:

a=Dict{String,Union{example3,UndefInitializer}}(currencies .=>undef)

However, for representing missing values the type Missing is usually more appropriate:

b=Dict{String,Union{example3,Missing}}(currencies .=>missing)

Please note that typeof(undef) yields UndefInitializer while typeof(missing) yields Missing - hence the need for Union types in the Dict. The dot (.) you can see above (.=>) is the famous Julia dot operator.

Moreover, I recommend to keep to Julia's naming conversion - struct and DataType names should start with a Capital Letter.

Last but not least, in your first example where concrete type Float64 was given, Julia has allocated the array to some concrete address in memory - beware that it can contain some garbage data (have a look at console log below):

julia> undef_array =  Array{example}(undef,3)
3-element Array{example,1}:
example(9.13315366e-316)
example(1.43236026e-315)
example(1.4214423e-316)