# Resolving UnionAlls with a single concrete instance in struct declarations

**URL:** <https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754>\
**Category:** Internals & Design\
**Created:** [April 17, 2026, 7:59pm UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754 "2026-04-17T19:59:36Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![brainandforce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brainandforce/32/211054_2.png) [@brainandforce](https://discourse.julialang.org/u/brainandforce)\
**Post date:** [April 17, 2026, 7:59pm UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/1 "2026-04-17T19:59:36Z")

</div>

This is something I’ve encountered far too often, and it’s one of my biggest gripes with Julia. @Tamas_Papp explained it best:

> [@"At present, Julia is a/an \_\_\_\_\_\_\_\_ programming language. " Fill in the blank with the most appropriate adjective](https://discourse.julialang.org/t/at-present-julia-is-a-an-programming-language-fill-in-the-blank-with-the-most-appropriate-adjective/134155/28):
>
> To be concrete, let me give an example. The other day a student asked me for help with optimizing a calculation. Since it involved lots of small matrices, I immediately suggested using `StaticArrays.SMatrix`. The student then did something not unlike this MWE:
> 
> ```julia-auto
> using StaticArrays
> 
> struct Foo{T,N}
> bar::SMatrix{N,N,T}
> end
> 
> ```
> 
> Now, seasoned Julia users can spot the problem quickly, which is easy to demo with
> 
> ```julia-auto
> julia> baz(foo::Foo) = sum(foo.bar)
> baz (generic function with 1 method)
> 
> julia> foo = Foo(SMatrix{3,3}(zeros(3,3)))
> Foo{Float64, 3}([0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])
> 
> julia> @code_warntype baz(foo)
> MethodInstance for baz(::Foo{Float64, 3})
> from baz(foo::Foo) @ Main REPL[10]:1
> Arguments
> #self#::Core.Const(Main.baz)
> foo::Foo{Float64, 3}
> Body::Any
> 1 ─ %1 = Main.sum::Core.Const(sum)
> │ %2 = Base.getproperty(foo, :bar)::SMatrix{3, 3, Float64}
> │ %3 = (%1)(%2)::Any
> └── return %3
> 
> ```
> 
> The problem is that `SMatrix{3,3,Float64}` is _not_ a concrete type, it is `SMatrix{3,3,Float64,9}`.

I’ve encountered issues with this in the past with CliffordNumbers.jl: subtypes of `AbstractCliffordNumber{Q,T}` need an extra type parameter (for instance, `KVector{K,Q,T,L}`) where `L` is the length of the backing `NTuple{L,T}`. For this type, `L = binomial(dimension(Q), K)`, so it’s not particularly simple arithmetic.

There’s good reason not to allow arbitrary computation in the type system, but this either becomes a pitfall for new Julia programmers, or an annoyance for those who have to leak type parameters when building a struct out of types like these.

Can there be a mechanism for the Julia compiler to resolve almost concrete types in struct declarations like `SMatrix{N,N,T}`, which only have a single concrete instance, to avoid the type instability and performance hit? Perhaps some sort of function, like

```julia-auto
Base.resolve_to_concrete_type(::Type{SMatrix{M,N,T}}) = SMatrix{M,N,T,M*N}

function Base.resolve_to_concrete_type(::Type{KVector{K,Q,T}}) where {K,Q,T}
    return KVector{K,Q,T,binomial(dimension(Q), K)}
end

```

which a user can opt into to cover cases like this?

---

<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:** [April 17, 2026, 9:49pm UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/2 "2026-04-17T21:49:57Z")

</div>

> [@brainandforce](#):
>
> `SMatrix{N,N,T}`, which only have a single concrete instance

Assuming you meant one instantiable concrete subtype, that’s entirely enforced by the implementation flagging or fixing an incomplete or inappropriate type like `SMatrix{2,2,Int,3}`, not the language itself. If we circumvent those methods with type piracy or the below hack, we can actually instantiate those inappropriate types:

```julia-auto
julia> x = eval(Expr(:new, SMatrix{2,2,Int,6}, Tuple(1:6)))
2×2 SMatrix{2, 2, Int64, 6} with indices SOneTo(2)×SOneTo(2):
 1 3
 2 4

julia> eachindex(x), x[5], x[6]
(SOneTo(4), 5, 6)

```

In the general case, omitted type parameters can more reasonably become non-redundant, and just as easily as extending `resolve_to_concrete_type`. Generic functions in the type computation e.g. `binomial`, `dimension` can get new, even impure, methods for new input types that violate implementation invariants. Adding new constructor methods can make exceptions to invariants. Omitting a type parameter e.g. `Foo{T,N,L}` to `Foo{T,N}` by computing a field parameter `SMatrix{N,N,T,N*N}` essentially amounts to putting “arbitrary computation in the type system”, dangerously brittle for a dynamic runtime and still questionable for AOT compilation. Pure built-ins or intrinsics on core types instead of generic functions e.g. `Base.mul_int(N, N)` could be more reasonable.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [April 18, 2026, 8:33am UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/3 "2026-04-18T08:33:46Z")

</div>

It’s a long story. At least from 2014: [RFC: staged / meta / generated types ? · Issue #8472 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/8472) and has come up many times (linked to in that issue), with various suggestions for how it can be solved.

---

<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:** [April 18, 2026, 8:39am UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/4 "2026-04-18T08:39:42Z")

</div>

> [@brainandforce](#):
>
> a mechanism for the Julia compiler to resolve almost concrete types in struct declarations like `SMatrix{N,N,T}`, which only have a single concrete instance, to avoid the type instability and performance hit?

Current best practice is to use a generic tool like JET to test for these instabilities, preferably in CI.

This is just _one_ possible type instability anyway. In complex codebases you need tooling to catch them all.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [April 20, 2026, 8:25am UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/5 "2026-04-20T08:25:55Z")

</div>

> [@brainandforce](#):
>
> Can there be a mechanism for the Julia compiler to resolve almost concrete types in struct declarations like `SMatrix{N,N,T}`, which only have a single concrete instance, to avoid the type instability and performance hit? Perhaps some sort of function

I once created and registered a package with this exact purpose, TypeCompletion.jl. Topic on Discourse:

- [[ANN] TypeCompletion.jl: exploit redundancy to complete UnionAll types](https://discourse.julialang.org/t/ann-typecompletion-jl-exploit-redundancy-to-complete-unionall-types/113987)

Disclaimer: I have not taken a look at that package for some time. It might not be well-maintained. It might not follow some best practice. The design might not be how I would do it if I were to do it today again.

If you are interested in maintaining/developing it, I can transfer or whatever.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 4, 2026, 5:02am UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/6 "2026-05-04T05:02:29Z")

</div>

> [@brainandforce](#):
>
> Can there be a mechanism for the Julia compiler to resolve almost concrete types in struct declarations like `SMatrix{N,N,T}`, which only have a single concrete instance, to avoid the type instability and performance hit?

Not quite the solution you are looking for, but I believe to a large extent you can avoid this problem by using functions as type aliases.

```julia-auto
SMatrixFun(M, N, T) = SMatrix{M, N, T, M*N}

```

Unfortunately, this pattern is viral. For your example `Foo` struct, you now have to do this.

```julia-auto
struct FooImpl{M}
    bar::M
end
Foo(T, N) = FooImpl{SMatrixFun(N, N, T)}

```

---

<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:** [May 4, 2026, 9:26am UTC](https://discourse.julialang.org/t/resolving-unionalls-with-a-single-concrete-instance-in-struct-declarations/136754/7 "2026-05-04T09:26:58Z")

</div>

I prefer to use a macro for this, because then it can have the same name (but be distinguished by the `@` sigil):

```julia-auto
macro SMatrix(ex)
    Base.isexpr(ex, :braces, 3) || error("Something informative...")
    N, M, T = (ex.args)
    quote
        N = $(esc(N))
        M = $(esc(M))
        SMatrix{N, M, $(esc(T)), N*M}
    end
end

```

```julia-auto
julia> @SMatrix{3, 2, Int}
SMatrix{3, 2, Int64, 6} (alias for SArray{Tuple{3, 2}, Int64, 2, 6})

```

Still viral though.
