Operation with struct parameter within struct definition

I want to make a struct where the second parameter used represents the dimensionality of the world, with scalar fields being N-dimensional arrays and vector fields being (N + 1)-dimensional arrays. Something like this:

struct Domain{T, N}
    scalar_fields::Array{T, N}
    vector_fields::Array{T, N + 1}
end

dom = Domain{Float64, 2}(zeros(Float64, 10, 10), zeros(Float64, 10, 10, 10))

This is not allowed since the + operation in being done within the struct definition with N is still a TypeVar, giving the error:

ERROR: MethodError: no method matching +(::TypeVar, ::Int64)

I am aware this could be technically accomplished by just omitting the dimension of the Array in the vector_fields definition and enforcing its dimension through a constructor but since Array{Float64} is not a concrete type, I’d rather not pay the performance cost and just hardcode it if it’s not possible.

Is there a way to do this properly?

I think the only way to do this to use another parameter,

struct Domain{T, N, M}
    scalar_fields::Array{T, N}
    vector_fields::Array{T, M}
end

and only use it for M == N+1. You could add this as a test inside a constructor. Such a test would be evaluated at compile-time, so that it doesn’t incur a runtime penalty.

1 Like

That would work, but hurts my OCD deeply.
Maybe I’ll end up doing it that way if there isn’t a nicer one so thanks!

From one of the “Related” threads that Discourse suggested below here:

Still uses an extra type parameter, but the constructor definition neatly makes it so that the redundant parameter doesn’t have to be explicitly given during struct instance initialization.

Another related thread recommended GitHub - vtjnash/ComputedFieldTypes.jl: Build types in Julia where some fields have computed types

1 Like