Function compiles twice but is called just once

Don’t take my comments for granted because these compiler topics are beyond my understanding, but I will try to comment on some of the details I have noticed.

Even though f seemingly was compiled just once, there are still two MethodInstances. Does the f(::Any) method instance have to do with the fact that f is a @generated function?

About the number of instances, I would say it has to do with the fact that Number is not a concrete type and not with the fact that it is a generated function.

julia> isconcretetype(Number)
false

I say this because if you define the type_unstable function without any type annotation and you run the function for concrete types, no f(::Any) function is generated.

julia> @generated function f(x)
           @info "Compiling f"
           return :(x + 1)
       end
f (generic function with 1 method)

julia> function type_unstable(y)
           @info "Running type_unstable"
           x = 2 * y[1]
           return f(x)
       end
type_unstable (generic function with 1 method)

julia> using MethodAnalysis

julia> type_unstable([1.0])
[ Info: Compiling f
[ Info: Running type_unstable
3.0

julia> methodinstances(f)
1-element Vector{Core.MethodInstance}:
 MethodInstance for f(::Float64)

julia> type_unstable([1])
[ Info: Compiling f
[ Info: Running type_unstable
3

julia> methodinstances(f)
2-element Vector{Core.MethodInstance}:
 MethodInstance for f(::Float64)
 MethodInstance for f(::Int64)

julia> type_unstable([ComplexF32(1.0)])
[ Info: Compiling f
[ Info: Running type_unstable
3.0f0 + 0.0f0im

julia> methodinstances(f)
3-element Vector{Core.MethodInstance}:
 MethodInstance for f(::Float64)
 MethodInstance for f(::Int64)
 MethodInstance for f(::ComplexF32)

julia> type_unstable(Number[1.0])
[ Info: Compiling f
[ Info: Running type_unstable
3.0

julia> type_unstable(Number[1.0])
methodinstances(f)
4-element Vector{Core.MethodInstance}:
 MethodInstance for f(::Float64)
 MethodInstance for f(::Int64)
 MethodInstance for f(::ComplexF32)
 MethodInstance for f(::Any)

But why is there only one Compiling f info statement that prints in this version of f?

It may (or may not) have something to do with something mentioned in the manual. From https://docs.julialang.org/en/v1/manual/metaprogramming/:

The number of times a generated function is generated might be only once, but it might also be more often, or appear to not happen at all. As a consequence, you should never write a generated function with side effects - when, and how often, the side effects occur is undefined…

2 Likes