Suppose I want to define a type People
that has two fields: names
and ages
. I would like names
to hold a Tuple
of String
objects, and ages
to hold a Tuple
of Int
objects. I would like both tuples to be of the same length.
I am currently parametrizing People
and using the type parameter as the length of each Tuple
.
struct People{N}
names::NTuple{N, String}
ages::NTuple{N, Int64}
end
Is this approach “correct”? I am asking because type parameters are supposed to define a family of types, and I am not exactly using the parameter for that purpose in this situation. Is there a nicer way of achieving the same result?
Thanks!
Looks alright to me. You may also want to use an array instead and check the fields are of the same length at runtime depending on what you will do with these structs.
2 Likes
I would just allow more general types, and use an inner constructor to validate, giving a nicer error than MethodError
. Eg
using ArgCheck
struct People{S <: Tuple{Vararg{<:AbstractString}}, T <: Tuple{Vararg{<:Integer}}}
names::S
ages::T
function People(names::S, ages::T) where {S, T}
@argcheck length(names) == length(ages)
new{S, T}(names, ages)
end
end
julia> People(("A", "B"), (25, 30))
People{Tuple{String,String},Tuple{Int64,Int64}}(("A", "B"), (25, 30))
julia> People(("A", ), (25, 30))
ERROR: ArgumentError: length(names) == length(ages) must hold. Got
length(names) => 1
length(ages) => 2
Stacktrace:
[1] macro expansion at /home/tamas/.julia/packages/ArgCheck/BUMkA/src/checks.jl:165 [inlined]
[2] People(::Tuple{String}, ::Tuple{Int64,Int64}) at ./REPL[8]:5
[3] top-level scope at none:0
1 Like