Create parametric structure with metaprogramming

I’m trying to use metraprogramming to create structures on the fly. I managed to make a construtor for a vanilla struct as:

function makestruct(name::Symbol, ndim::Integer)
    dims = (:x, :y, :z)
    fields = [:( $(dims[i]) ) for i in 1:ndim]
    @eval begin
        struct $(name)
            $(fields...)
        end
    end
end

However, I can’t manage to make a parametric struct with metaprogramming. In the end what I would like to simply generate:

struct bar{T}
    x::T
    y::T
end

or

struct bar{T}
    x::T
    y::T
    z::T
end

depending on ndim

It seems like your existing code is already almost there–you just need to add T in the appropriate places:

julia> function makestruct(name::Symbol, ndim::Integer)
           dims = (:x, :y, :z)
           fields = [:( $(dims[i])::T ) for i in 1:ndim]
           @eval begin
               struct $(name){T}
                   $(fields...)
               end
           end
       end
makestruct (generic function with 1 method)

julia> makestruct(:bar, 2)

julia> bar(1, 2)
bar{Int64}(1, 2)

1 Like

Oh thanks :smiley: I was unsuccesfuly trying to parse the ::T directly inside the eval call

By the way, you might be interested in StaticArrays.FieldVector, which is designed to let types like this operate as statically sized vectors in a convenient way: API · StaticArrays.jl

Oh, and also, if your actual use-case really is small vectors with x, y, z labels, note that you can already use StaticArrays.SVector for that with no changes at all:

julia> using StaticArrays

julia> v = SVector{2, Float64}(1.0, 2.0)
2-element SVector{2, Float64} with indices SOneTo(2):
 1.0
 2.0

julia> v.x
1.0

julia> v.y
2.0

Thanks for the suggestion, but in this particular case x, y, z will either be 2 or 3 dimensional arrays too large for StaticArrays.

1 Like