# Tuple and NamedTuple types

**URL:** <https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701>\
**Category:** General Usage\
**Tags:** type, tuple, parametric-types, namedtuple\
**Created:** [December 28, 2021, 11:58am UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701 "2021-12-28T11:58:20Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [December 28, 2021, 11:58am UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/1 "2021-12-28T11:58:20Z")

</div>

Dear all,

I have some trouble to infer the types of Tuples and NamedTuples. Let’s start with a simple tuple. If each field in the tuple is of the same type, I can state the type of the tuple as follows (MWE):

```julia
a = (:b, :c, :d)
typeof(a) #Tuple{Symbol, Symbol, Symbol}
typeof(a) <: NTuple{k, Symbol} where k #true

```

1. **Question**

Let’s say now that I define a custom struct and I want that the tuple can only hold the custom structs, but the struct itself has parametric types. How can I force the tuple to only hold such custom structs? MWE:

```julia
struct Test1{A, B}
	a	::	A
	b ::	B
end

b = (Test1("1", :b), Test1(3., 4), )
typeof(b) #Tuple{Test1{String, Symbol}, Test1{Float64, Int64}}
typeof(b) <: NTuple{k, T} where {k, T<:Test1} #false

```

This would be useful to me if I want to have a field of another struct to only hold tuples of Test1 types. I can already do something more general, but  
any tuple could be inserted, which is not what I want.

```julia
struct BigStruct{A<:Tuple}
	a :: A
end
BigStruct(b) #working

```

I would like to force that field `a` can only hold Tuples of Test1 types:

```julia
struct SafeBigStruct{k, T<:Test1}
	a :: NTuple{k, T}
end
SafeBigStruct(b) # NOT working -> no method matching SafeBigStruct...

```

1. **Question**

Extending this to NamedTuples, how would this work? As far as i understand, NamedTuple types contain the types of its keys and values:

```julia
c = (d = Test1("1", :d), e = Test1(3., 4), )
typeof(c) #NamedTuple{(:d, :e), Tuple{Test1{String, Symbol}, Test1{Float64, Int64}}}

```

The key values should always have type `NTuple{k, Symbol} where k`, but just as in the previous question, I cannot infer the value types. Is there any way to get the NamedTuple type, such that it still enforces that all values have to be of type `Test1`?

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [December 28, 2021, 1:24pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/2 "2021-12-28T13:24:55Z")

</div>

**Question 1:** the type `NTuple{k, T} where {k, T<:Test1} ` doesn’t work because that defines a tuple type where all values are the _same_ subtype of `Test1`. Indeed it works if you have `Test1` instances of the same concrete type:

```julia
julia> (Test1("1", :b), Test1("2", :c)) isa NTuple{k, T} where {k, T<:Test1}
true

```

(Note that instead of `typeof(x) <: T` I used the simpler form `x isa T`.)

What you want is still easy to achieve because tuples (unlike other types in Julia) are covariant. For example one has `Tuple{Int,Float64} <: Tuple{Number,Number}` (no need to write `<:Number`). Similarly in your case you can use:

```julia
julia> b isa NTuple{K, Test1} where K
true

```

and there’s even a short version for this using `Vararg`:

```julia
julia> b isa Tuple{Vararg{Test1}}
true

```

**Question 2:** for named tuples it’s trickier because they are not covariant, but since the types are encoded with a tuple (which is covariant) it’s still easy to do:

```julia
julia> c isa NamedTuple{names, <:Tuple{Vararg{Test1}}} where {names}
true

```

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [December 28, 2021, 1:25pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/3 "2021-12-28T13:25:27Z")

</div>

Let’s focus on the first `Tuple` question first.

```julia
struct Test1{A, B}
  a::A
  b::B
end

test1x = Test1("one", Int8(1))  
# Test1{String, Int8}("one", 1)
test1y = Test1('1', UInt16(1))  
# Test1{Char, UInt16}('1', 0x0001)
test1 = (test1x, test1y)
# ( Test1{String, Int8}("one", 1), 
# Test1{Char, UInt16}('1', 0x0001) )

typeof(test1) 
# Tuple{Test1{String, Int8}, Test1{Char, UInt16}}

typeof(test1) <: Tuple{Vararg{Test1, N}} where {N}
# true

```

The use of this type constraining pattern

- `Tuple{ Vararg{T,N} } where {T,N}`  
is more flexible than
- `NTuple{N,T} where {N,T}`

> notice that the order of the parameters in `Vararg{T,N}` is swapped with respect to the order in `NTuple{T,N}`  
> _I would like to see that changed_

```julia
wrapped_typename(::Type{T}) where {T} = T.name.wrapper
wrapped_typename(x::T) where {T} = wrapped_typename(T)
wrapped_typename(x::UnionAll} = x

unwrapped_typename(::Type{T}) where {T} = T
unwrapped_typename(x::T) where {T} = T

wrapped_unwrapped(::Type{T}) where {T} =
  (wrapped_typename(T), unwrapped_typename(T))
wrapped_unwrapped(x::T) where {T} = wrapped_unwrapped(T)

```

```julia
julia> wrapped_unwrapped(Int16)
(Int16, Int16)

julia> wrapped_unwrapped(Rational{Int32})
(Rational, Rational{Int32})

julia> wrapped_unwrapped(Rational{Int64})
(Rational, Rational{Int64})

julia> wrapped_unwrapped(test1x)
(Test1, Test1{String, Int8})

julia> wrapped_unwrapped(test1)
(Tuple, Tuple{Test1{String, Int8}, Test1{Char, UInt16}})

julia> typeof(test1)
Tuple{Test1{String, Int8}, Test1{Char, UInt16}}

```

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [December 28, 2021, 3:57pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/4 "2021-12-28T15:57:09Z")

</div>

> [@sijo](#):
>
> `Tuple{Vararg{Test1}}`

Thanks a lot for your detailed answer! Just to confirm, `Tuple{Vararg{Test1}}` is not a concrete type? For instance, the following field type might result in a speed loss:

```julia
struct SafeBigStruct2
	a :: Tuple{Vararg{Test1}}
end
SafeBigStruct2(b)

```

I can circumvent that (and still enforce the `Test1` tuple) by doing the following, though:

```julia
struct SafeBigStruct3{K<:Tuple{Vararg{Test1}}}
	a :: K
end
SafeBigStruct3(b)

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [December 28, 2021, 4:01pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/5 "2021-12-28T16:01:14Z")

</div>

Yes I think that’s exactly right, though in this case I would probably go back to `NTuple` and write

```julia
struct SafeBigStruct4{K}
    a :: NTuple{K, Test1}
end

```

(Edit: that’s not doing what is desired which is a struct type with concrete field types, see below)

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [December 28, 2021, 4:11pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/6 "2021-12-28T16:11:16Z")

</div>

Thank you! But BigStruct4 would also not be concrete, right?

```julia
SafeBigStruct3(b) #SafeBigStruct33{Tuple{Test1{String, Symbol}, Test1{Float64, Int64}}}
SafeBigStruct4(b) #SafeBigStruct4{2}

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [December 28, 2021, 4:24pm UTC](https://discourse.julialang.org/t/tuple-and-namedtuple-types/73701/7 "2021-12-28T16:24:16Z")

</div>

Oops sorry you’re right of course!

```julia
s3 = SafeBigStruct3(b)
s4 = SafeBigStruct4(b)

julia> isconcretetype(fieldtype(typeof(s3), :a))
true

julia> isconcretetype(fieldtype(typeof(s4), :a))
false

```
