Help defining a custom SVector

The StaticArrays.jl documentation mentions the FieldVector abstract type that developers can use to inherit all the nice behavior of SVector:

using StaticArrays

struct Vec{T} <: FieldVector{3,T}
  x::T
  y::T
  z::T
end

Now, any instance v = Vec{T} will have getindex and setindex! properly defined as well as all the fast basic math operations with vectors and matrices. The docstring of FieldVector also mentions that it is nice to implement

StaticArrays.similar_type(::Type{<:Vec3}, ::Type{T}, s::Size{(3,)}) where {T} = Vec3{T}

to get the correct return type in array expressions. Is this still updated information? It seems that just the subtyping in the struct definition already handles everything?

My main question is actually the following: how to define a type Vec{Dim,T} that has length fixed at compile time but free as a variable in the code? I am looking into something like:

struct Vec{Dim,T} <: FieldVector{Dim,T}
  ... # what goes here?
end

To give some context, I am trying to write an exact replacement for SVector. In particular, it is possible to type SVector(1,2,3) and let the constructor figure out the length 3 and the type Int, or explicitly ask for SVector{3,Float64}(1,2,3) to convert to double precision.

1 Like
struct Vec{Dim,T} <: FieldVector{Dim,T}
   xs::Tuple{Dim, T}
end

Base.length(v::Vec{Dim, T}) where {Dim, T} = Dim
1 Like

Thank you @jling, can you provide a full example of usage? I tried instantiating the vector and it didn’t work saying that it has no static size.

What you’re looking for here is not a FieldVector, since the number of fields you want depends on the type parameter.

This will require a bit more work than using FieldVector but is probably a better idea anyways. I’d do something like:

using StaticArrays

struct Vec{L, T} <: StaticVector{L, T}
    v::SVector{L, T}
    Vec{L, T}(v::SVector{L, T}) where {L, T} = new{L, T}(v)
end

Base.getindex(v::Vec, i::Int) = getindex(v.v, i)
Base.size(v::Vec, i) = size(v, i)

Vec(args...) = Vec(SVector(args...))
Vec(sv::SVector{L, T}) where {L, T} = Vec{L,T}(sv)

and then just define whatever extra methods you end up needing.

Thank you @Mason, I will try to copy/paste many FieldVector definitions and wrap everything into a single generic Vec. Maybe that works?

Isn’t what you want just the SVector{N,T} ? As I understand FieldVector allows the access of elements by name, but if you have a variable number of fields that does not make immediate sense.

(from the last part of your question, you want an exact reimplementation of SVectors, but with a different type signature, for some particular dispatch?

there has been a recent question about using something like const Vec = SVector, which does not work because it only defines an alias, and from what I remember there was no easy solution rather than re-implementing everyting again).

Yes, I want everything that SVector provides but with a type that I own for two reasons:

  1. I would be able to write outer constructors that always convert Integer coordinates to AbstractFloat.
  2. This type would be isolated from other ecosystems and therefore even if someone starts adding methods for SVector out there in the wild, that would not interfere with the compilation of packages.

This is the GitHub issue behind this discussion:

1 Like

No, you shouldn’t use FieldVector for this. You should just make a type that wraps an SVector, since you aren’t actually accessing by field.

2 Likes