In a much larger code, we’re having some issues with type inference in a custom getproperty()
function. Here’s a minimal example demonstrating at least part of the problem:
mutable struct MyElement{T}
name :: String
value :: T
_filled::Set{Symbol}
_frozen::Bool
_in_expression::Vector{Symbol}
end
function Base.getproperty(elm::MyElement, field::Symbol)
return _getproperty(elm, field)
end
function _getproperty(elm::MyElement, field::Symbol)
value = getfield(elm, field)
return customget(elm, field, value)
end
function customget(elm::MyElement, field::Symbol, value)
if field in (:value, :other)
return value
else
return value
end
end
This is obviously contrived and our actual code has a series of other checks and such, but I’ve stripped that all out. Nevertheless, if I run in Julia 1.11.1:
using BenchmarkTools
f(elm) = elm.value
elm = MyElement("", 1.0, Set([:value]),false, Symbol[])
@btime f($elm)
I get 26.525 ns (1 allocation: 16 bytes). Cthulhu analysis reveals that the compiler has trouble inferring the type of value
in _getproperty
here, but I can’t figure out why. If I make even minor changes the code, it works fine. Things I’ve tried that result in proper inference (~2 ns and 0 allocations) include:
- Removing any of the other fields from the definition of MyElement
- Combining
Base.getproperty
and_getproperty
or_getproperty
andcustomget
- Tagging
_getproperty
with@inline
So I have two questions:
- Why is the code above type unstable?
- Why is the code inference so fragile to minor changes?