Difference between Type{T} and T when passing type variable inside generated function?

Why passing type argument into @generated function changes its value from T into Type{T}?

function type_print(T)
  return :(println($T))

macro type_print(T)
  return :(println($T))

@generated function type_print_gen(T)
  return :(println($T))

type_print(Int8) |> eval # Int8
@type_print(Int8) # Int8
type_print_gen(Int8) # Type{Int8} - why???

Because of that, I cannot write generated functions that call another functions that use types as input variables, e.g. read(io::IO, T), typemax(T) and so on.

Just wondering, why are you using a generated function? It’s almost never the right choice.

I want to generate the most efficient code to read binary stream into given combination of types. Simply generate repeating reads given a tuple of types. See #2 here, and further performance comparison.

julia> @generated function type_print_gen(T)
         return :(println(T))
type_print_gen (generic function with 1 method)

julia> type_print_gen(Int8)

But this is probably more along the lines of what you want:

julia> foo(::Type{Type{T}}) where {T} = T
foo (generic function with 1 method)

julia> @generated function type_print_gen(T)
type_print_gen (generic function with 1 method)

julia> type_print_gen(Int32)
1 Like

Thank you!
Is there any reason for such specific behaviour?

So my final code looks like this:

foo(::Type{Type{T}}) where {T} = T

# from Tuple{T1, T2, ...} - generate (read(io, T1), read(io, T2), ...)
@generated function read_gen(io::IOBuffer, types::Type...)
    Expr(:tuple, [Expr(:call, :read, :io, foo(i)) for i in types]...)

io = IOBuffer(UInt8[0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00])
types = (Int8, Int16, Int32)
read_gen(io, types...)

You can’t interact with values in generated functions, but you can with the types of arguments.
So it’s often more convenient to use the arguments directly (as types) than have to type every argument to the function. This is especially true with varargs.

julia> @generated function foo(a, b...)
           @show a b
foo (generic function with 1 method)

julia> foo((1,0xcf,1f0,1.0), "hi", "world", 3.14, :π, π)
a = Tuple{Int64,UInt8,Float32,Float64}
b = (String, String, Float64, Symbol, Irrational{:π})
(String, String, Float64, Symbol, Irrational{:π})