Understanding how subtypes work within NamedTuple

This is just how the Julia type system is designed. Tuple types are contravariant, and they’re, in fact, the only non-invariant concrete types (hope I’m not misusing terminology):

julia> NamedTuple{(:a, :b),Tuple{Int, Int}} <: NamedTuple{(:a, :b),Tuple{Real, Real}}
false

julia> Tuple{Int} <: Tuple{Real}
true

Relevant FAQ entry (especially the second paragraph):
Frequently Asked Questions · The Julia Language?

For more, see the Julia Manual, and perhaps even Wikipedia.

BTW, another, more general, approach for your “workaround” would be something like this:

julia> testG(x::NamedTuple{syms, <:NTuple{n, Real}}) where {syms, n} = print(x)
testG (generic function with 1 method)

julia> testG((a = 1, c = 3))
(a = 1, c = 3)
julia> testG((z = 4.3, r = big"5"))
(z = 4.3, r = 5)

This should work for any NamedTuple, as long as all values are subtypes of Real.

3 Likes