Dynamic creation of similar structs

question
data_structures

#1

Julia does not permit such syntax but what I want is basically

struct A{T, 2}
    x::T
    y::T 
end

struct A{T, 3}
    x::T
    y::T
    z::T
end

struct A{T, 4}
    x::T
    y::T
    z::T
    w::T
end

i.e., the number in type parameter matches the number of fields. The fields could contain x, y, z, w, a, b, c, d..., and so on.
Is there a way of doing this?


#2

A FieldVector comes close
http://juliaarrays.github.io/StaticArrays.jl/stable/pages/api.html#FieldVector-1


#3

Thank you, I know FieldVector, but what I am concerned here is that why I should have

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

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

struct A4{T}
    x::T
    y::T
    z::T
    w::T
end

rather than generating the fields dynamically? The As are closely related and I do not want 3 types. Sorry, I should have been clearer.


#4

Why does it have to be fields? Maybe a single (named) tuple as a replacement is fine? You could even overwrite getproperty to make it feel like fields.


#5

That’s a good idea. But I am just curious about whether Julia provides us such capability.


#6

You can overload getproperty to get the behavior you like without enumerating types.

julia> struct A{N, Ttuple <: NTuple{N}}
               t::Ttuple
       end

julia> function Base.getproperty(a::A{N}, s::Symbol) where {N}
               s === :x && N >= 1 && return getfield(a, :t)[1]
               s === :y && N >= 2 && return getfield(a, :t)[2]
               s === :z && N >= 3 && return getfield(a, :t)[3]
               s === :w && N >= 4 && return getfield(a, :t)[4]
               return getfield(a, s)
       end

julia> a = A((1,2,3,4));

julia> a.x
1

julia> a.y
2

julia> a.z
3

julia> a.w
4

julia> a = A((1,2,3));

julia> a.w
ERROR: type A has no field w
Stacktrace:
 [1] getproperty(::A{3,Tuple{Int64,Int64,Int64}}, ::Symbol) at .\REPL[45]:6


#7

Do you want to generate the values dynamically, or the valid field names?


#8

Why would you do this and not use a NamedTuple?

julia> a = (x=1, y=2, z=3)
(x = 1, y = 2, z = 3)

julia> a.x
1

julia> a.y
2

julia> a.z
3

julia> a.w
ERROR: type NamedTuple has no field w
Stacktrace:
 [1] getproperty(::Any, ::Symbol) at .\sysimg.jl:18

#9

Pure laziness to type x =, y = etc.


#10

You can easily create a “constructor”,

julia> function A(v)
          k = (:x, :y, :z, :w)
          NamedTuple{k[eachindex(v)]}(v)
       end
A (generic function with 1 method)

julia> a = A((1,2,3))
(x = 1, y = 2, z = 3)

julia> a = A((1,2,3,4))
(x = 1, y = 2, z = 3, w = 4)

EDIT: A(v) isn’t type stable here which could easily be healed if we restrict the input to be Tuples.


#11

I want to generate the valid field names dynamically.


#12

If you want the a.b syntax, you should probably define methods for Base.propertynames and Base.getproperty. See the docs.