# How can I create type stable stable tuples with non-concrete parameters (or: Invariant tuple types)

**URL:** https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627
**Category:** General Usage
**Created:** [February 17, 2022, 1:32pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627 "2022-02-17T13:32:34Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [February 17, 2022, 1:32pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/1 "2022-02-17T13:32:34Z")

</div>

Hey all,

So, I made this script where I have a type like this:

```julia
struct Foo
    v::NTuple{8, Union{String, Nothing}}
end

```

The reason being that I want the compiler to be able to enforce a length of 8 for me, and also that a an object more lightweight than an array wouldn’t be bad, either.

However, code involving `Foo` is inherently type unstable because:

```julia
julia> isconcretetype(NTuple{8, Union{String, Nothing}})
false

```

Which is due to tuples being co-variant in their type parameters.

Is there any way for me to use tuples - or something like tuples - such that they can be concretely typed, while also containing Union elements?

Here are the approaches I’ve tried

- Use an `SVector` from StaticArrays.jl. Doesn’t work - since StaticArrays implements SVector with tuples, it’s still type unstable
- Just use a vector, then check during instantiation that the length of the vector is 8. Doable, but not _that_ nice - for example, the compiler cannot tell me if I accidentally mess up the lengths, and cannot automatically elide bounds checks etc.
- Wrap the union in a struct `Bar`, then have `Foo` contain `NTuple{8, Bar}`. This is the solution I ended up going with (using ErrorTypes.jl), and it does work, but I’m wondering if I missed anything simpler.

---

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [February 17, 2022, 1:45pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/2 "2022-02-17T13:45:35Z")

</div>

Perhaps dumb suggestion, but if `length(v)` is always 8, perhaps your type `Foo` could basically implement a `Tuple` of length 8? Eg.

```julia
struct Foo{8 type parameters}
    v1
    v2
    etc...
end

```

?

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [February 17, 2022, 1:45pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/3 "2022-02-17T13:45:55Z")

</div>

I think you can’t get more type stable than this:

```julia
julia> struct Foo3{T<:NTuple{8,Union{String,Nothing}}}
           v::T
       end

julia> x = Foo3(ntuple(i -> i < 4 ? "a" : nothing, 8))
Foo3{Tuple{String, String, String, Nothing, Nothing, Nothing, Nothing, Nothing}}(("a", "a", "a", nothing, nothing, nothing, nothing, nothing))

julia> x = Foo3(ntuple(i -> i < 4 ? "a" : nothing, 7))
ERROR: MethodError: no method matching Foo3(::Tuple{String, String, String, Nothing, Nothing, Nothing, Nothing})
Closest candidates are:
  Foo3(::T) where T<:NTuple{8, Union{Nothing, String}} at REPL[7]:2
Stacktrace:
 [1] top-level scope
   @ REPL[9]:1

```

but that will put quite a price on the compiler, as all objects will have different types, dispatch on that will be probably a mess.

To be truth, I’m not sure this has any advantage over the original proposal, unless you the positions of the `nothing`s and `strings` are the same on every object at the end, in which case functions could specialize to that exact structure. Otherwise anything operating on these or those objects will end up doing run-time dispatch anyway.

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [February 17, 2022, 1:53pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/4 "2022-02-17T13:53:36Z")

</div>

That would probably be even worse, since it not only have to do runtime dispatch, but also compile new methods for every variant of the tuple.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [February 17, 2022, 2:06pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/5 "2022-02-17T14:06:14Z")

</div>

Wouldn’t that happen to anything you do with those tuples at the end? Seems to me that it is hard do _not_ end up with a 2^8 dispatch table somewhere, by using any of these approaches.

---

<div class="post-metadata">

### Author: ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)
#### Post date: [February 17, 2022, 2:14pm UTC](https://discourse.julialang.org/t/how-can-i-create-type-stable-stable-tuples-with-non-concrete-parameters-or-invariant-tuple-types/76627/6 "2022-02-17T14:14:28Z")

</div>

No, using the struct approach, the tuple itself is type stable, and the only instability is when the `Union{Nothing, String}` is accessed, in which case union-splitting will take care of it.
