I have created an MWE that can readily executed by copy-pasting to the REPL, provided package DispatchDoctor.jl is installed.
What follows below is:
-
A variable
Z
is created in global scope (see end of script below). -
A function
mwe
that, according to DispatchDoctor.jl, exhibits type instability when called withmwe(Z)
. The instability comes from an inner function calledlowerbound
. Functionlowerbound
defines in its body two anonymous¹ functions that are never called. -
A function
mwe_2
that is identical tomwe
, but where the first anonymous function that is never called is now commented out. When called withmwe_2(Z)
, no type instability is detected. -
A function
mwe_3
that is identical tomwe
, but where the second anonymous function that is never called is now commented out. When called withmwe_3(Z)
, no type instability is detected.
My question: why do the two redundant anonymous function influence the type instability?
¹ As pointed out below by @nsajko, these are not actually anonymous functions. I point out the mistake here, but do not correct it above so that the comment below does not appear out of place.
using DispatchDoctor
function mwe(Z)
local kernel(xᵢ, xⱼ, σf, ℓ) = σf * exp( - abs2(xᵢ - xⱼ) * ℓ)
@stable function lowerbound(σf, ℓ)
local k(x, z) = kernel(x, z, σf, ℓ) # this is never called
local k(x) = kernel.(x, Z, σf, ℓ)
local s(x) = dot(k(x), k(x)) # this is never called
return k(1.0)
end
lowerbound(1.0, 1.0)
end
# same as mwe but line "local s(x) = dot(k(x), k(x))" is commented out
function mwe_2(Z)
local kernel(xᵢ, xⱼ, σf, ℓ) = σf * exp( - abs2(xᵢ - xⱼ) * ℓ)
@stable function lowerbound(σf, ℓ)
local k(x, z) = kernel(x, z, σf, ℓ) # this is never called
local k(x) = kernel.(x, Z, σf, ℓ)
# local s(x) = dot(k(x), k(x)) # this is never called
return k(1.0)
end
lowerbound(1.0, 1.0)
end
# same as mwe but line "local k(x, z) = kernel(x, z, σf, ℓ)" is commented out
function mwe_3(Z)
local kernel(xᵢ, xⱼ, σf, ℓ) = σf * exp( - abs2(xᵢ - xⱼ) * ℓ)
@stable function lowerbound(σf, ℓ)
# local k(x, z) = kernel(x, z, σf, ℓ) # this is never called
local k(x) = kernel.(x, Z, σf, ℓ)
local s(x) = dot(k(x), k(x)) # this is never called
return k(1.0)
end
lowerbound(1.0, 1.0)
end
# I am aware that this is a *non-const* global
Z = collect(LinRange(0, 30, 30));
mwe(Z) # type instability detected
mwe_2(Z) # NO type instability detected
mwe_3(Z) # NO type instability detected