# Subtyping \`NamedTuple\`s in \`NamedTuple\`s

**URL:** <https://discourse.julialang.org/t/subtyping-namedtuple-s-in-namedtuple-s/123747>\
**Category:** General Usage\
**Tags:** question\
**Created:** [December 12, 2024, 9:22am UTC](https://discourse.julialang.org/t/subtyping-namedtuple-s-in-namedtuple-s/123747 "2024-12-12T09:22:35Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![benedikt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benedikt/32/214130_2.png) [@benedikt](https://discourse.julialang.org/u/benedikt)\
**Post date:** [December 12, 2024, 9:22am UTC](https://discourse.julialang.org/t/subtyping-namedtuple-s-in-namedtuple-s/123747/1 "2024-12-12T09:22:35Z")

</div>

I don’t understand the following behavior:

```julia
julia> typeof((a = (b = 1,),)) <: NamedTuple{(:a,), Tuple{<:NamedTuple}}
false

julia> typeof((a = (b = 1,),)) <: NamedTuple{(:a,), Tuple{NT}} where {NT <: NamedTuple}
true

```

---

<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:** [December 12, 2024, 12:32pm UTC](https://discourse.julialang.org/t/subtyping-namedtuple-s-in-namedtuple-s/123747/2 "2024-12-12T12:32:59Z")

</div>

This is due to two confusing things:

1. `Tuple` is covaritant w.r.t its type parameters, whereas `NamedTuple` is invariant.
2. `A{B{C}} where {C <: D}` is different from `A{(B{C} where {C <: D})}`. In the former, `B` is treated as a `TypeVar`, so it’s equivalent to `A{<:B{C<:D}}`.

So, let’s look at `(a = (b = 1,),)`.:

- Its type is `NamedTuple{(:a,), Tuple{NamedTuple{(:b,), Tuple{Int}}}}`
- Therefore, it’s also a subtype of the `UnionAll` type `NamedTuple{(:a,), <:Tuple}`.
  - This is because `Tuple{NamedTuple{(:b,), Tuple{Int}}}} <: Tuple`

- However, it’s NOT a subtype of the _concrete_ type `NamedTuple{(:a,), Tuple}`, which is what your first line queries, because `NamedTuple` is invariant.

Your second line has `NamedTuple{(:a,), Tuple{NT}} where {NT <: NamedTuple}`.

- Since the `where` is outside the outer parenthesis, there `where` applies to the outermost `NamedTuple` - in other words, it makes the `NamedTuple` a `UnionAll`
- That means it’s equivalent to `NamedTuple{(:a,), <:Tuple{<:NamedTuple}}`. And this is clearly a correct supertype
- Alternatively, `NamedTuple{(:a,), (Tuple{NT} where {NT <: NamedTuple})}` is NOT a supertype of the given name dtuple, because the `where` is inside the outer parenthesis

---

<div class="post-metadata">

**Author:** ![benedikt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benedikt/32/214130_2.png) [@benedikt](https://discourse.julialang.org/u/benedikt)\
**Post date:** [December 12, 2024, 3:12pm UTC](https://discourse.julialang.org/t/subtyping-namedtuple-s-in-namedtuple-s/123747/3 "2024-12-12T15:12:33Z")

</div>

Thanks for the quick reply and the explanation regarding `UnionAll` types 👍
