# Creating many large arrays within structs

Suppose I have an (immutable) struct that holds many large arrays. Not all of these arrays need to exist, however, it just depends on the user-specified problem setup. So I defined my struct like this:

``````@with_kw struct mystruct
a::Union{Nothing,Matrix{Float64}} = nothing
b::Union{Nothing,Matrix{Float64}} = nothing
c::Union{Nothing,Matrix{Float64}} = nothing
d::Union{Nothing,Matrix{Float64}} = nothing
end
``````

Now I have some methods that initialize this struct differently depending on what the user specifies:

``````function init_my_struct(::Val{1})
return mystruct(a=zeros(500,500),b=zeros(500,500))
end

function init_my_struct(::Val{2})
return mystruct(c=zeros(500,500),d=zeros(500,500))
end

function init_my_struct(::Val{3})
return mystruct(a=zeros(500,500),b=zeros(500,500),c=zeros(500,500),d=zeros(500,500)),
end
``````

(I’m dispatching by value just to highlight the three different cases).

If you notice, the third case is really just a combination of the first two cases. In this particular example, it is easy to manually rewrite out each case. But in my actual code, I have many cases for dozens of arrays…

Is there an efficient way to pass blocks of parameters like this? Maybe via metaprogramming?

I thought about writing another function (one for each case) which simply returns a vector of all the arrays for that particular case, then I could splat them as needed. However, this seems extremely inefficient as that would effectively allocate each array twice

I appreciate the help!

Would named tuples work for you?

``````julia> ab = (a=zeros(2, 2), b=zeros(2, 2))
(a = [0.0 0.0; 0.0 0.0], b = [0.0 0.0; 0.0 0.0])

julia> cd = (c=zeros(2, 2), d=zeros(1, 1))
(c = [0.0 0.0; 0.0 0.0], d = [0.0;;])

julia> abcd = (; ab..., cd...)
(a = [0.0 0.0; 0.0 0.0], b = [0.0 0.0; 0.0 0.0], c = [0.0 0.0; 0.0 0.0], d = [0.0;;])
``````

Here, the splatting allocates a new tuple, but does not allocate the arrays inside the fields

``````julia> ab.a[1, 2] = 1
1

julia> abcd
(a = [0.0 1.0; 0.0 0.0], b = [0.0 0.0; 0.0 0.0], c = [0.0 0.0; 0.0 0.0], d = [0.0;;])
``````

and can be easily passed to your struct as well:

``````julia> mystruct(; ab...)
mystruct
a: Array{Float64}((2, 2)) [0.0 1.0; 0.0 0.0]
b: Array{Float64}((2, 2)) [0.0 0.0; 0.0 0.0]
c: Nothing nothing
d: Nothing nothing
``````
2 Likes

What is the advantage of immuatbility of your struct here ? I think it is not necessary, but of course I don’t know your context.

If you can tolerate mutability, you could make your entries unions like e.g. here, so that you can maintain type stability.

Here, the splatting allocates a new tuple, but does not allocate the arrays inside the fields

Hey, this is clever! This works well, thank you!

These arrays are going through many loops over and over. I’m passing the struct containing all these arrays all over the place. I assumed it would help performance if I kept it immutable.

If you can tolerate mutability, you could make your entries unions like e.g. here , so that you can maintain type stability.

Is this not what I’m already doing above? What does mutability buy you here?

``````@with_kw struct mystruct
a::Union{Nothing,Matrix{Float64}} = nothing
b::Union{Nothing,Matrix{Float64}} = nothing
c::Union{Nothing,Matrix{Float64}} = nothing
d::Union{Nothing,Matrix{Float64}} = nothing
end
``````
1 Like