StaticArrays, parametric types, type stability

Here is a little snippet of code

using StaticArrays

struct JustMyType{N,M}
    a::Vector{<:SMatrix{N,M,Float64}}
    b::         SMatrix{N,M,Float64}
end

j = JustMyType([SMatrix{2,3,Float64}(randn(2,3)) for i=1:4],
                SMatrix{2,3,Float64}(randn(2,3))            )

Note the <: . My previous version of the code without it fails, because SMatrix{N,M,Float64} is an abstract type (the single concrete type corresponding to it being SMatrix{N,M,Float64,N*M}.

  1. Coding
    a::Vector{SMatrix{N,M,Float64,N*M}}

does not work - one cannot multiply type parameters.

  1. For some reason I do not understand, but likely related to N*M not being legit, the developers of StaticArrays.jl had to have a length parameter to an SMatrix. One way I could write my code is to let JustMyType also have this parameter. However, I am not keen, because in a real world situation with many StaticArrays in my type, this generates many parameters, a source of bugs and poor readability of code and typeofoutputs.

  2. As coded now, my structure has fields of abstract types, and I am set for type-unstable code.

I’ll have to chose between readability and performance, unless you can point out something I missed!

Your requirements are not very clear, but something like

struct JustMyType{T}
    a::Vector{T}
    b::T
end

should work.

Don’t overtype things. If absolutely necessary, you can make T <: AbstractMatrix, or validate that it is an SMatrix in the constructor, or use a triangular parametrization like

struct JustMyType{N,M,T<:SMatrix{N,M}}
    a::Vector{T}
    b::T
end

you need N and M as a type parameter directly.

3 Likes

I forgot to mention, as you propose

struct JustMyType{T}
    a::Vector{T}
    b::T
end

which I had in a previous version of my code. It’s neat and performant code. However, the real-world equivalent (a structure with many different arrays) of typing typeof(j)returns a type description with the detailed description of the type of all these arrays. I want the user of my code to have a “friendly” relation to typeof(j).

So to be more specific. I wish to refactor the above code to have

  • few type parameters - not having to provide L which is obviously M times N
  • integer type parameters (for readability of the concrete type of j), so T is not welcome.
  • type stability (no abstract fields).

Is that at all possible?

:grinning:

Sorry, I do not understand what you mean here.

The type system is not the place to express these kind of constraints. Extra type parameters of this kind are standard in Julia, and generally innocuous. You can, of course, design your user-facing API so that L does not need to be specified by the user — see how StaticArrays does it.

The static arrays have elements have themselves complicated elements, so using your T patterm in a previous version of my real world code, typeof would return between 5 and 10 lines of hard-to-read details, and I was not happy with that.

As I said, I was fishing for ideas, but I believe now I was aware of all the options. I have now gone for a solution in which I accept the small annoyance of having L (and its real-world siblings) as an extra parameter to my type.

Tamas, it’s not the first time you help me: thank you again! :grinning:

1 Like

Yes, that’s a known issue, and people are working on it, see eg

Happy to help!

1 Like

Also consider using the macros defined by ConcreteStructs.jl! They can simplify some of these extraneous type parameters, and will give you more terse and readable type printouts for free. I find it makes working with these parametric structs a bit more user friendly.

3 Likes

but… this is gold! :grinning: I’ll have to play with it to understand the full potential