# Fragile type inference in custom getproperty()

**URL:** https://discourse.julialang.org/t/fragile-type-inference-in-custom-getproperty/122268
**Category:** Performance
**Tags:** question, compilation
**Created:** [November 5, 2024, 2:03am UTC](https://discourse.julialang.org/t/fragile-type-inference-in-custom-getproperty/122268 "2024-11-05T02:03:08Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![bclyons12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bclyons12/32/33734_2.png) [@bclyons12](https://discourse.julialang.org/u/bclyons12)
#### Post date: [November 5, 2024, 2:03am UTC](https://discourse.julialang.org/t/fragile-type-inference-in-custom-getproperty/122268/1 "2024-11-05T02:03:08Z")

</div>

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:

```julia
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:

```julia
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` and `customget`
- Tagging `_getproperty` with `@inline`

So I have two questions:

1. Why is the code above type unstable?
2. Why is the code inference so fragile to minor changes?

---

<div class="post-metadata">

### Author: ![lkdvos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lkdvos/32/43091_2.png) [@lkdvos](https://discourse.julialang.org/u/lkdvos)
#### Post date: [November 5, 2024, 2:53am UTC](https://discourse.julialang.org/t/fragile-type-inference-in-custom-getproperty/122268/2 "2024-11-05T02:53:02Z")

</div>

In principle, these functions are inherently type unstable, in the sense that you need to know the value of the propertyname in order to figure out the return type. Of course, in the specific case of `getproperty`, that would be terrible, since these functions are always called like that. For this reason, the compiler has special rules for `getproperty`, effectively telling it to always try to constant-propagate. If the property name is a compile-time constant, the functions become type stable again.  
This special behavior is reserved for `getproperty` and does not automatically carry over to your own `_getproperty` functions, making them type-unstable again. Typically, you can resolve this by telling the compiler to try and propagate constants: (`Base.@constprop`) [Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#Base.@constprop).  
Alternatively, inlining the functions also migrates them back to the constant-propagated-`getproperty`. Finally, the compiler may decide on it’s own that this function is worth constant propagating, or inlining, depending on compiler heuristics.
