In the code snippet below the function make_foo() returns either Bar or Baz depending on the value of its input. In the actual code the determination of the type and actual construction of the result include some long computations; the type stability is therefore not an issue. The results are then stored in a collection, and due to performance considerations I prefer to store the results in two separate arrays (Vector{Bar} and Vector{Baz}) rather than putting everything in a Vector{Union{Bar,Baz}}. In the same time, it is desirable to cache the position of the result in the collection as a function of input. In the code below this is achieved by storing the position in a dictionary with the values of type Tuple{DataType, Int}, where the first element always equals either Bar or Baz, and the second is the index in the corresponding array. However, I have an impression that this is not quite a julian way of doing things…
Is there a better approach to this problem?
module Scratch
struct Bar
x::Int
end
struct Baz
x::Int
end
const Foo=Union{Bar,Baz}
make_foo(x::Int)::Foo = (x%2==0) ? Bar(x) : Baz(x)
struct Data
bar::Vector{Bar}
baz::Vector{Baz}
dic::Dict{Int,Tuple{DataType,Int}}
end
Data()=Data(Vector{Bar}(), Vector{Baz}(), Dict{Int,Tuple{DataType,Int}}())
function _add!(d::Data, b::Bar)
push!(d.bar, b)
length(d.bar)
end
function _add!(d::Data, b::Baz)
push!(d.baz, b)
length(d.baz)
end
function add!(d::Data, f::Foo)
haskey(d.dic, f.x) && throw(DomainError("Duplicate data"))
n=_add!(d,f)
d.dic[f.x]=(typeof(f),n)
end
function main()
d=Data()
for i=1:10
add!(d, make_foo(i))
end
d
end
end