Functions passed functions as arguments will automatically specialize if they call said function.

That is

```
inner(f,x) = f(x) # sort function args first to support `do` syntax
```

should specialize because it is calling `f`

, but

```
pass(f,x) = inner(f,x)
```

won’t necessarilly, because it isn’t calling `f`

.

Let’s use `@noinline`

to try and make this more clear.

```
function outer000(f) # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f,x)
return f(2*x)
end
@noinline function pass(f,x)
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer001(f) # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f::Fi,x) where {Fi}
return f(2*x)
end
@noinline function pass(f,x)
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer010(f) # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f,x)
return f(2*x)
end
@noinline function pass(f::Fp,x) where {Fp}
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer011(f) # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f::Fi,x) where {Fi}
return f(2*x)
end
@noinline function pass(f::Fp,x) where {Fp}
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer100(f::Fo) where {Fo} # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f,x)
return f(2*x)
end
@noinline function pass(f,x)
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer101(f::Fo) where {Fo} # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f::Fi,x) where {Fi}
return f(2*x)
end
@noinline function pass(f,x)
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer110(f::Fo) where {Fo} # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f,x)
return f(2*x)
end
@noinline function pass(f::Fp,x) where {Fp}
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
function outer111(f::Fo) where {Fo} # 0 v 1 bools on specialization for outer, pass, inner
@noinline function inner(f::Fi,x) where {Fi}
return f(2*x)
end
@noinline function pass(f::Fp,x) where {Fp}
return inner(f,x)
end
out = zeros(1000)
for i = 1:1000
out[i] = pass(f,i)
end
out
end
```

This yields:

```
f(x) = exp(x)
julia> @btime outer000(f);
46.415 μs (1979 allocations: 38.84 KiB)
julia> @btime outer001(f);
47.216 μs (1979 allocations: 38.84 KiB)
julia> @btime outer010(f);
46.122 μs (1979 allocations: 38.84 KiB)
julia> @btime outer011(f);
45.612 μs (1979 allocations: 38.84 KiB)
julia> @btime outer100(f);
37.679 μs (1979 allocations: 38.84 KiB)
julia> @btime outer101(f);
38.109 μs (1979 allocations: 38.84 KiB)
julia> @btime outer110(f);
12.724 μs (1 allocation: 7.94 KiB)
julia> @btime outer111(f);
12.402 μs (1 allocation: 7.94 KiB)
```

It’s the two functions not calling `f`

that matter – they must either inline or specialize.