Consider a simple example where I perform something inside an array A based on some co-ordinate information (abstract type CoOrdinateInfo).
I have two possible cases.
- Regular view of an array, with all elements that have to be processed.
struct CoOrdinateInfoUnMasked <: CoOrdinateInfo
Begin::NTuple{2,Int}
Size::NTuple{2,Int}
end
- Masked view of an array, with only the valid elements to be processed.
struct CoOrdinateInfoMasked <: CoOrdinateInfo
Begin::NTuple{2,Int}
Mask::Array{Bool,2}
end
Now I create an array CoOrdinateInfos::Array{CoOrdinateInfo,2} which is either updated by the user by modifying elements in place or utilized for doing something on A using an element CoOrdinateInfos[dim1,dim2]. In both cases we can extract the size (in the masked case size(Info.Mask) will give the size)
This of course creates allocations since none of the code has a clue about what the type is.
Note: The performance even with allocations is very good for my use case but would like to remove allocations to guarantee better timing since its used in a reactive program and be able to potentially compile to smaller binaries.
I am trying to see what’s the best way to optimize my code further.
One simple way is to just collapse both into one struct
struct CoOrdinateInfo
Begin::NTuple{2,Int}
Size::NTuple{2,Int}
Mask::Array{Bool,2}
end
and set mask to be an array of 0 size if it is non sparse and just write a simple check at the calling function based on this (Most of these choices are runtime anyway since the data is very adaptive). But this can be hard to scale if I had more parameters or more variants to account for. Additionally, I have found most of my Julia code to be self-documenting, and this goes against that principle a little bit.
I am sure that some kind of packing heterogeneous information into a homogeneous container is required (unless there’s optimizations that can look into the worst-case size of all possible combinations and allocate along with a tag like a symbol, somewhat like a lisp machine), but I’m curious of elegant ways to do it while the general code looks very readable. Something like a macro or something that would combine to get a set of fields for a given set of information types (essentially a macro that emulates a lisp machine on my current machine). Is what I’m looking for called sum types/tagged union? (are Enums and traits related in any way)?
If there’s a package that can handle these scenarios with additional configurability, can I have an example of how to replicate the above case, and if possible additional things I could do.