Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to get the return type of a Julia function in an unevaluated context?

Tags:

julia

I want to get the result type of a function call in Julia without evaluating the function, and use that type. The desired usage looks somewhat like this:

foo(x::Int32) = x
foo(x::Float32) = x

y = 0.0f0
# Assert that y has the type of result of foo(Float32)
y::@resultof foo(Float32) # This apparently does not work in Julia

While in the case above, I can simply use y::typeof(foo(1.0f0)) with evaluation of a dummy variable, in more complicated cases, initializing a dummy variable might be inconvenient and expensive. For example, I want to use the iterator type returned by function eachline(filename::AbstractString; keep::Bool=false), but using the typeof really requires opening a file successfully, which looks like an overkill.

From a C++ background, what I am asking is that is there an equivalent of std::result_of in Julia. The question is almost the same as this one but the language is Julia.


After some research I see that Julia allows for return value of different types in one function, where the type inference looks very hard. For example,

foo(x::Int64) = x == 1 ? 1 : 1.0

The return type can now be Int64 or Float64, depending on the input value. Nevertheless, in this case, I am still wondering if there are some macro tricks that can deduce that the return type is of Union{ Int64, Float64 }?


To summarize, my questions are:

  1. Fundamentally, is it possible to get the function return type by only supplying argument types in Julia?
  2. If 1 is not possible, for functions that have one deterministic return type (as in the 1st example), is it possible to get the return type unevaluated?
  3. (Might be unrelated with what I want but I think it can boost my understanding) When Julia codes are compiled, are the return types of the functions known? Or is the type information only determined at run time?
like image 331
drel Avatar asked Oct 10 '19 17:10

drel


1 Answers

1) Yes, Base.return_types(foo, (Int64,)) will return an array containing the return type you're asking for, i.e. Union{ Int64, Float64 } in this case. If you drop the second argument, a tuple specifying the input argument types, you'll get all possible infered return types.

It should be noted, however, that the compiler might at any point decide to return Any or any other correct but imprecise return type.

2) see 1) ?

3) For given input argument types, the compiler tries to infer the return type at compile-time. If multiple are possible, it will infer a Union type. If it fails completely, or there are too many different return types, it will infer Any as the return type. In the latter cases, the actual return type is only known at runtime.

Demonstration of 1):

julia> foo(x::Float32) = x
foo (generic function with 1 methods)

julia> foo(x::Int32) = x
foo (generic function with 2 methods)

julia> foo(x::Int64) = x == 1 ? 1 : 1.0
foo (generic function with 3 methods)

julia> Base.return_types(foo)
3-element Array{Any,1}:
 Union{Float64, Int64}
 Int32
 Float32

julia> Base.return_types(foo, (Int64,))
1-element Array{Any,1}:
 Union{Float64, Int64}

julia> Base.return_types(foo, (Int32,))
1-element Array{Any,1}:
 Int32
like image 73
carstenbauer Avatar answered Nov 03 '22 21:11

carstenbauer