# SMatrix{2, 2, Float64} is not a concrete type?

**URL:** <https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638>\
**Category:** General Usage\
**Tags:** bug, code\_warntype, type-stability, staticarrays\
**Created:** [October 6, 2023, 12:05am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638 "2023-10-06T00:05:23Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)\
**Post date:** [October 6, 2023, 12:05am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/1 "2023-10-06T00:05:23Z")

</div>

I’m writing some program which for the sake of aesthetics manipulates data as SMatrix{2,2, Float64}. However, I noticed that, having a collection of such SMatrices, say in variable `Ms`, the command `sum(Ms)` allocates memory. Insdeed,

```julia
using StaticArrays
Ms = Vector{SMatrix{2, 2, Float64}}();
for i in 1:1000
       push!(Ms, SMatrix{2, 2, Float64}(rand(2,2)))
end
@time sum(Ms)
# 0.000053 seconds (999 allocations: 46.828 KiB)
isconcretetype(SMatrix{2,2,Float64})
# false

```

Indeed, calling `@code_warntype sum(Ms)` produces

```julia
MethodInstance for sum(::Vector{SMatrix{2, 2, Float64}})
  from sum(a::AbstractArray; dims, kw...) @ Base reducedim.jl:994
Arguments
  #self#::Core.Const(sum)
  a::Vector{SMatrix{2, 2, Float64}}
Body::Any
1 ─ nothing
│ %2 = Base.:(:)::Core.Const(Colon())
│ %3 = Core.NamedTuple()::Core.Const(NamedTuple())
│ %4 = Base.pairs(%3)::Core.Const(Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}())
│ %5 = Base.:(var"#sum#807")(%2, %4, #self#, a)::Any
└── return %5

```

showing an errant `Any`. Surely this is not the intended behavior of `StaticArrays`? Is there a workaround?

---

<div class="post-metadata">

**Author:** ![danielmatz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielmatz/32/2285_2.png) [@danielmatz](https://discourse.julialang.org/u/danielmatz)\
**Post date:** [October 6, 2023, 12:19am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/2 "2023-10-06T00:19:18Z")

</div>

This gets me all the time, too! There’s a fourth type parameter that you are missing. You need `SMatrix{2, 2, Float64, 4}`. That final parameter is the total number of elements in the array.

```julia
julia> isconcretetype(SMatrix{2, 2, Float64, 4})
true

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 6, 2023, 5:55am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/3 "2023-10-06T05:55:01Z")

</div>

The reason this last parameter is required, as far as I have understood, is that the type system cannot perform arithmetic, and thus cannot figure out that `2*2 = 4`. For the compiler to know the length of the backing tuple that is required to store all the data, you thus have to provide the `4` as well.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [October 6, 2023, 7:11am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/4 "2023-10-06T07:11:34Z")

</div>

> [@baggepinnen](#):
>
> the type system cannot perform arithmetic

Basically nothing but subtyping can be done to type parameters because methods are so malleable. Imagine you have `twice(x::Int) = 2x` and somehow could do `Rectangle{L, W=twice(L)}` so that `Rectangle{L}` is concrete. But then you do `twice(x::Int) = 3x` so `Rectangle{L}` means something different and the existing instances become invalid. Complete type chaos. Just because `Rectangle{1, 3}` was impossible before doesn’t mean it won’t always be, so it’s good to keep all the parameters even if the type constructors’ bodies make some of them redundant at the moment.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 6, 2023, 11:39am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/5 "2023-10-06T11:39:19Z")

</div>

> [@bremez](#):
>
> `Ms = Vector{SMatrix{2, 2, Float64}}()`

Use something like

```julia
Ms = Vector{typeof(zero(SMatrix{2,2,Float64}))}()

```

to calculate the accidental type parameters.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 6, 2023, 11:54am UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/6 "2023-10-06T11:54:43Z")

</div>

I’ve opened an issue for this with a suggested interface for turning something like `SMatrix{2, 2, Float64}` into `SMatrix{2, 2, Float64, 4}`: [Add a function to get the computed field types from an incomplete `StaticArray` type · Issue #1206 · JuliaArrays/StaticArrays.jl · GitHub](https://github.com/JuliaArrays/StaticArrays.jl/issues/1206)

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 6, 2023, 1:11pm UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/7 "2023-10-06T13:11:36Z")

</div>

Interesting. Is this something that could and should, and not too late(?), have been handled by a macro?

Maybe that’s exactly the reason from the docs:

> A convenience macro `@SMatrix [1 2; 3 4]` is provided

Preceding:

> Statically sized `N×M` matrices are provided by `SMatrix{N,M,T,L}`.
> 
> Here `L` is the `length` of the matrix, such that `N × M = L`. However,  
> convenience constructors are provided, so that `L`, `T` and even `M` are  
> unnecessary. At minimum, you can type `SMatrix{2}(1,2,3,4)` to create a 2×2  
> matrix (the total number of elements must divide evenly into `N`).

So this “convenience constructor” is for _in_convenience? 🙂 I guess it’s to help to not have to know too much, and sometimes parts of code aren’t the bottleneck. But I’m not sure then you would want to be using SMatrix… Is this maybe better when L is rather large (but not too large then just go with regular Matrix?)? Should there be a warning or error when L is low. That seems like a breaking change… but might be ok.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [October 6, 2023, 3:03pm UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/8 "2023-10-06T15:03:59Z")

</div>

Those are convenience constructors for _instances_. With a couple parameters _and_ the inputs, it can work out and apply the remaining parameters. But the problem in the original post was not about constructing an instance, but was about specifying a container for holding instances of some type. When specifying a type separate from an instance (e.g., in struct fields or container parameters), it’s necessary to specify it fully. In method signatures for dispatch and object constructors that can successfully infer the remaining parameters, it is not necessary to specify types fully.

I try to use `map` or comprehensions (wherever possible) when constructing containers. They do a good job of correctly and automatically determining the proper container type. Doing these sorts of things by hand is pretty tedious and error-prone.

Also, note that

```julia
push!(Ms, SMatrix{2, 2, Float64}(rand(2,2)))

```

is allocating and filling a 2x2 `Matrix{Float64}` first, then using those values to build a `SMatrix` before discarding the `Matrix`. You should try `@SArray randn(2,2)` or `randn(SMatrix{2,2})` instead, which will not create the temporary array.

---

<div class="post-metadata">

**Author:** ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)\
**Post date:** [October 9, 2023, 2:51pm UTC](https://discourse.julialang.org/t/smatrix-2-2-float64-is-not-a-concrete-type/104638/9 "2023-10-09T14:51:12Z")

</div>

Thank you everyone for the quick responses! @danielmatz that indeed solved my allocation issue.

@baggiponte @Benny I indeed came across this in a different setting, when I wanted to define a `struct MyBuffer{N}` that holds two `SVectors`, one of length `N` and one of length `6*N`, but to no avail. I understand how the this is circumvented by custom constructors that enforce such invariants - are there any other standard practices?

More broadly, I’m terribly confused my the (sometimes, partial) syntax of parametric type specification when invoking constructors. By now I understand that sometimes they can be omitted if types are inferable from the constructor arguments, but then, which are skippable? Is the situation different between inner and “external” constructors? It seems to me the documentation on writing (sanitized, idiomatic) constructors is very thin.
