Great question.
I also posted on using the methods
method to see what specializations were happening or not happening. This is how I check myself to see if I understand what Julia is doing under-the-hood.
Here’s the version with no specialization:
julia> f(T::Type) = T
f (generic function with 1 method)
julia> methods(f).ms[1].specializations
svec()
julia> f(Int64)
Int64
julia> methods(f).ms[1].specializations
svec(#undef, #undef, #undef, #undef, #undef, #undef, #undef, MethodInstance for f(::Type{T} where T))
julia> f(Float64)
Float64
julia> methods(f).ms[1].specializations
svec(#undef, #undef, #undef, #undef, #undef, #undef, #undef, MethodInstance for f(::Type{T} where T))
Despite calling f
with both Int64
and Float64
as arguments, only a single MethodInstance
is needed to handle both arguments.
Here is the version with specialization:
julia> g(::Type{T}) where T = T
g (generic function with 1 method)
julia> methods(g).ms[1].specializations
svec()
julia> g(Int64)
Int64
julia> methods(g).ms[1].specializations
svec(MethodInstance for g(::Type{Int64}), #undef, #undef, #undef, #undef, #undef, #undef, #undef)
julia> g(Float64)
Float64
julia> methods(g).ms[1].specializations
svec(MethodInstance for g(::Type{Int64}), MethodInstance for g(::Type{Float64}), #undef, #undef, #undef, #undef, #undef, #undef)
Now we have a MethodInstance
that is specialized for Int64
and another MethodInstance
that is specialized for Float64
.
methods
returns a Base.MethodList
with two fields, ms
and mt
. ms
is just a Vector{Method}
. mt
is a Core.MethodTable
. Both contain a wealth of information about the resulting methods.