So in the end I think I’ve gotten what I needed, and agree that I over complicated it. I’m subtyping StaticVector, but calling StaticVector directly actually produces the same error:
julia> StaticVector{6,Float64}(rand(6))
ERROR: DimensionMismatch: No precise constructor for StaticArray{Tuple{6}, Float64, 1} found. Length of input was 6.
Stacktrace:
[1] _no_precise_size(SA::Type, x::NTuple{6, Float64})
@ StaticArrays C:\Users\jonda\.julia\packages\StaticArrays\dTwvg\src\convert.jl:161
[2] construct_type(#unused#::Type{StaticArray{Tuple{6}, Float64, 1}}, x::StaticArrays.Args{Tuple{Tuple{NTuple{6, Float64}}}})
@ StaticArrays C:\Users\jonda\.julia\packages\StaticArrays\dTwvg\src\convert.jl:81
[3] StaticArray (repeats 2 times)
@ C:\Users\jonda\.julia\packages\StaticArrays\dTwvg\src\convert.jl:165 [inlined]
[4] convert
@ C:\Users\jonda\.julia\packages\StaticArrays\dTwvg\src\convert.jl:204 [inlined]
[5] StaticArray{Tuple{6}, Float64, 1}(a::Vector{Float64})
@ StaticArrays C:\Users\jonda\.julia\packages\StaticArrays\dTwvg\src\convert.jl:174
[6] top-level scope
@ REPL[11]:1
and so I have to define the struct with data::NTuple{X,T}, where I explicitly define X (unless I define a constructor as @mbauman recommended? more in a sec).
But my interface is typically not StaticVector{N,T}, typically we define SVector{N,T}. Changing the alias definition gets me I believe exactly what I want, and now that I’m reading back I think this is what @abraemer was recommending.
So now this works as I was hoping:
using StaticArrays
const A{N,T} = SVector{N,T}
const B{N,T} = A{N,T}
const C{N,T} = A{N,T}
const D{T} = B{3,T}
const E{T} = B{3,T}
const F{T} = C{3,T}
const G{T} = C{4,T}
f(d::D) = d.*d
f(g::G) = g + g
f2(a::A) = sqrt.(a)
julia> d = D([3,3,3])
3-element SVector{3, Int64} with indices SOneTo(3):
3
3
3
julia> g = G([3,3,3,3])
4-element SVector{4, Int64} with indices SOneTo(4):
3
3
3
3
julia> f(d)
3-element SVector{3, Int64} with indices SOneTo(3):
9
9
9
julia> f(g)
4-element SVector{4, Int64} with indices SOneTo(4):
6
6
6
6
julia> f2(d)
3-element SVector{3, Float64} with indices SOneTo(3):
1.7320508075688772
1.7320508075688772
1.7320508075688772
julia> f2(g)
4-element SVector{4, Float64} with indices SOneTo(4):
1.7320508075688772
1.7320508075688772
1.7320508075688772
1.7320508075688772
But back on @mbauman response. I see what you’re saying about the partially filled parameters and needing to create our own constructors to cover missing parameters. I do still need the methods and behavior of SVectors on my types however, so I (maybe mistakenly?) assumed that subtyping was a must. Is there a way to maintain the behavior of SVectors in your example without subtyping?
In the end, had I wanted to use StaticVector{N,T} rather than SVector {N,T}, the constructor did solve my problem of “how do I pass N to the call for NTuple,” even while super typing.
struct H{N,T} <: StaticVector{N,T}
data::NTuple{N,T}
end
@inline Base.getindex(A::H, i::Int64) = (@boundscheck checkbounds(A,i); A.data[Base.to_index(i)])
(::Type{H{N}})(d::NTuple{N,T}) where {N,T} = H{N,T}(d)
const H2 = H{3}
julia> H{3}(rand(3))
3-element H{3, Float64} with indices SOneTo(3):
0.2669897586332304
0.20288500609093174
0.08817405671923229
julia> H2(rand(3))
3-element H2{Float64} with indices SOneTo(3):
0.421901093230018
0.6764301848959721
0.3690068074848969
Thanks for the help! Trying to take the time to really understand these concepts.