I need to work with a set of points that might each have a different type. Consider as a rough example:
abstract type AbstractLabel end
struct LabelA <: AbstractLabel end
struct LabelB <: AbstractLabel end
struct LabelC <: AbstractLabel end
struct PointWithLabel{L<:AbstractLabel}
xy::Vector{Float64}
label::Type{L}
PointWithLabel(x::Float64, y::Float64, label::Type{L}) where {L} = new{L}([x, y], label)
PointWithLabel(x, y, label) = PointWithLabel(Float64(x), Float64(y), label)
PointWithLabel{L}(x, y) where {L} = PointWithLabel(x, y, L)
end
const PointA = PointWithLabel{LabelA}
const PointB = PointWithLabel{LabelB}
const PointC = PointWithLabel{LabelC}
I could then define for example the vector
p1 = PointA(0.5, 0.3)
p2 = PointB(0.17, -0.3)
p3 = PointC(0.0, 0.0)
p4 = PointB(0.2, 0.5)
vec1 = [p1, p2, p3, p4]
4-element Vector{PointWithLabel}:
PointA([0.5, 0.3], LabelA)
PointB([0.17, -0.3], LabelB)
PointC([0.0, 0.0], LabelC)
PointB([0.2, 0.5], LabelB)
Alternatively, I could define the vector as
vec2 = Vector{PointWithLabel{L} where L}([p1, p2, p3, p4])
4-element Vector{PointWithLabel{L} where L}:
PointA([0.5, 0.3], LabelA)
PointB([0.17, -0.3], LabelB)
PointC([0.0, 0.0], LabelC)
PointB([0.2, 0.5], LabelB)
Which of these vectors would be better to work with for performance? I’ll be e.g. solving differential equations with many thousands of these types of points, and using the labels in the type of the point to exploit multiple dispatch for defining new addition formulas (e.g. +(::PointA, ::PointB)
and +(::PointC, ::PointA)
). I initially thought vec1
would be better since the element type is not concrete, !isconcretetype(PointWithLabel)
, although vec2
requires me to define methods specific for the type PointWithLabel{L} where L
. Alternatively, I could work with a Vector{Union{PointA, PointB, PointC}}
, but I remember from somewhere (I think) that unions are not always performant.