I have a working Point
type that works smoothly in 2D and 3D with various outer constructors:
using StaticArrays
struct Point{Dim,T}
coords::SVector{Dim,T}
end
# convenience constructors
Point{Dim,T}(coords::NTuple{Dim,V}) where {Dim,T,V} = Point{Dim,T}(SVector(coords))
Point{Dim,T}(coords::Vararg{V,Dim}) where {Dim,T,V} = Point{Dim,T}(SVector(coords))
Point(coords::NTuple{Dim,T}) where {Dim,T} = Point{Dim,T}(SVector(coords))
Point(coords::Vararg{T,Dim}) where {Dim,T} = Point{Dim,T}(SVector(coords))
Point(coords::AbstractVector{T}) where {T} =
Point{length(coords),T}(SVector{length(coords)}(coords))
# coordinate type conversions
Base.convert(::Type{Point{Dim,T}}, coords) where {Dim,T} = Point{Dim,T}(coords)
Base.convert(::Type{Point{Dim,T}}, p::Point) where {Dim,T} = Point{Dim,T}(p.coords)
Base.convert(::Type{Point}, coords) = Point{length(coords),eltype(coords)}(coords)
# type aliases for convenience
const Point2 = Point{2,Float64}
const Point3 = Point{3,Float64}
const Point2f = Point{2,Float32}
const Point3f = Point{3,Float32}
I can for example create the following points:
# most commonly used
Point((1,2)) # figures out that (Dim, T) = (2, Int)
Point(1,2) # the same without the extra parenthesis
Point([1, 2]) # from a vector because most users expect it to work
# forcing different types
Point{2,Float32}((1.0,2.0)) # converts from Float64 to Float32
Point{2,Float32}(1.0, 2.0) # the same without parenthesis
# with cleaner syntax
Point2f((1.0,2.0)) # same as previous section
Point2f(1.0, 2.0) # same as previous section
# converting from array syntax
Point2f[(1,2), (3,4)] # vector of points with Float32 coordinates
The problem starts when I try to do the same with 1D points, i.e. a single coordinate. The code enters in an infinite loop because the outer Vararg
constructor keeps calling itself as opposed to calling the inner constructor with SVector
:
Point(1.0) # infinite loop here
Point((1.0,)) # the same infinite loop
I expected a Point{1,Float64}
as the result. Is this intended behavior? How can I preserve the functionality above and still handle the 1D case? I appreciate any help, I’ve been struggling with this dispatch rule for a while now, and other people are trying to help too (cc: @FPGro).