Specialisation rules for function objects and type parameters

I think I might have just answered my own question. It will specialize to Wrapper{typeof(sin)}, but not if Wrapper <: Function:

julia> struct Wrapper{F<:Function}
           f::F
       end

julia> struct Wrapper2{F<:Function} <: Function
           f::F
       end

julia> (w::Wrapper{F})(x) where {F} = w.f(x)

julia> (w::Wrapper2{F})(x) where {F} = w.f(x)

julia> f_func(f, num) = ntuple(f, div(num, 2))

julia> f_func(sin, 5); f_func(Wrapper(sin), 5); f_func(Wrapper2(sin), 5)
(0.8414709848078965, 0.9092974268256817)

julia> Base.specializations(@which f_func(sin, 5))
Base.MethodSpecializations(svec(MethodInstance for f_func(::Wrapper{typeof(sin)}, ::Int64), MethodInstance for f_func(::Function, ::Int64), nothing, nothing, nothing, nothing, nothing))

So we can see there is f_func(::Wrapper{typeof(sin)}, ::Int64). But since Wrapper2 <: Function, it results in no specialisation!

1 Like