# Specialisation rules for function objects and type parameters

**URL:** <https://discourse.julialang.org/t/specialisation-rules-for-function-objects-and-type-parameters/128991>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 14, 2025, 10:10am UTC](https://discourse.julialang.org/t/specialisation-rules-for-function-objects-and-type-parameters/128991 "2025-05-14T10:10:07Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 14, 2025, 10:10am UTC](https://discourse.julialang.org/t/specialisation-rules-for-function-objects-and-type-parameters/128991/1 "2025-05-14T10:10:07Z")

</div>

The Julia [docs](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing) say:

> [@](#):
>
> These will not specialize:
> 
> ```julia
> f_func(f, num) = ntuple(f, div(num, 2))
> g_func(g::Function, num) = ntuple(g, div(num, 2))
> 
> ```
> 
> but this will:
> 
> ```julia
> h_func(h::H, num) where {H} = ntuple(h, div(num, 2))
> 
> ```

I am wondering if this applies recursively or not? For example,

```julia
struct Wrapper{F<:Function}
    f::F
end
(w::Wrapper{F})(x) where {F} = w.f(x)

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

```

Would `f_func` specialise to the _type parameter_ of `Wrapper`? For example if I write

```julia
f_func(Wrapper(sin), 5)

```

would `f_func` specialise to `Wrapper{typeof(sin)}` even though it does not specialise to `typeof(sin)` itself?

Furthermore, would it change if I declare `Wrapper{F} <: Function`?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 14, 2025, 10:15am UTC](https://discourse.julialang.org/t/specialisation-rules-for-function-objects-and-type-parameters/128991/2 "2025-05-14T10:15:37Z")

</div>

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

```julia-repl
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!

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 14, 2025, 11:29am UTC](https://discourse.julialang.org/t/specialisation-rules-for-function-objects-and-type-parameters/128991/3 "2025-05-14T11:29:39Z")

</div>

This is exactly as described in the manual. The compiler just _mechanically_ skips specializations for `Type`, `Function`, and `Vararg`. Eg in the following example, the type is not even callable, but since it is `<:Function`, the rule still applies:

```julia
struct Foo{T} <: Function
    x::T
end

bar(f::Foo) = f.x # ain' t calling anything

f = Foo(2)

bar(f)

Base.specializations(@which bar(f)) # empty

```

But of the 3 exceptions above, you can only do this trick with `Function`, as the compiler complains if you try to subtype `Vararg` and `Type`.
