Capturing the types of the values, from the type of a Named Tuple


Given the type of a NamedTuple, I want to make operations on the types of the values (or fields) of the type, ultimately to compute a new type and allocate memory.

Here is a little code

function see(::Type{NT}) where{K,V,NT<:NamedTuple{K,V}} 
    @show K
    @show V
function see(::Type{V}) where{A,B,V<:Tuple{A,B}}     
    @show A,B

T = typeof((a=(1,2.),b=:hi))

which displays

K = (:a, :b)
V = Tuple{Tuple{Int64, Float64}, Symbol}
(A, B) = (Tuple{Int64, Float64}, Symbol)

as wanted: A, and B contain the types of the values of a variable of type T.

So far so good. The catch is, I want to be able to analyse the type T of NamedTuples of arbitrary length. Nothing loath, I try

function see(::Type{V}) where{A...,V<:Tuple{A...}}     
    @show A...

but get the error

ERROR: syntax: invalid variable expression in "where" 
around [the new method]

So slurping isn’t the thing in where constructs. New attempt

function see(::Type{V}) where{A,V<:Tuple{A}}     
    @show A

where I again hope A will be a Tuple of Types.

ERROR: MethodError: no method matching 
see(::Type{Tuple{Tuple{Int64, Float64}, Symbol}})
Closest candidates are: [...]

Any clever ideas?

julia> typeof.(values((a = 1.0, b = 1, c = "A")))
(Float64, Int64, String)

With this you get the types from the values. For tuples that should be quite general, since the tuple type is by definition that of the values. Not sure if that helps.

1 Like

Hi Imiq,

Thank you. That would work (actually, I did implement something along those lines), but I was trying to create functions that operate purely on the types.

In other words: if I give you

typeof((a = 1.0, b = 1, c = "A"))

as input, do you know any way to give me back

(Float64, Int64, String)

that is not specific to the length of the input NamedTuple?

I’m not sure if I understand the question:

julia> t(x) = (typeof.(values(x)))
t (generic function with 1 method)

julia> t((a=1.0, b=1, c="A"))
(Float64, Int64, String)

julia> t((a=1.0, b=1))
(Float64, Int64)

How to operate on the type directly I don’t know. But that, for tuples is probably not particularly useful (at least I do not see how it could be).

EDIT: hidden because this is terrible and should not be done

This is using internals and is highly discouraged: It may break in any future release and it might be broken for certain uses currently.

julia> t = Tuple{Int,Float64}
Tuple{Int64, Float64}

julia> t.types
svec(Int64, Float64)

I think that #53193 tangentially relates to this, although that is dealing with Union rather than Tuple.

I would encourage you to give a little more info about your problem. It may be that there is an idiomatic way to achieve what you want that doesn’t require this type of thing.

Not sure this answers the question, but maybe fieldtypes does what you’re looking for:

julia> nt = (a = 1.0, b = 1, c = "A")
(a = 1.0, b = 1, c = "A")

julia> T = typeof(nt)
@NamedTuple{a::Float64, b::Int64, c::String}

julia> fieldtypes(T)
(Float64, Int64, String)


BINGO!!! Thank you!!!

Imiq, since you ask about the context: I want to preallocate memory for information (in nested structures of Tuples and NamedTuples, where the Float64’s can be replaced by ForwardDiff-type variables.

Case closed. Thank you, friends!