# Type-inference and the dot operator

**URL:** <https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432>\
**Category:** Internals & Design\
**Created:** [May 18, 2024, 1:46pm UTC](https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432 "2024-05-18T13:46:36Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)\
**Post date:** [May 18, 2024, 1:46pm UTC](https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432/1 "2024-05-18T13:46:36Z")

</div>

I had naively assumed the type-inference used only the types of the arguments to a function call then realized that in an important special case - the dot operator - it must be able to use the value of the second argument. For a composite type `foo` the type of `foo.bar` depends on the value, `:bar`, not just the fact that this argument is of type Symbol.

I can see how it would be possible to infer the type of `foo.bar` in the days when the foo.bar meant `getfield(foo, :bar)` but now that it means `getproperty(foo, :bar)` and it is possible to have custom getproperty methods for a type I’m a bit confused as to how it works. Is there an explanation somewhere of how type inference reacts with constant propagation for cases like this?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [May 18, 2024, 3:03pm UTC](https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432/2 "2024-05-18T15:03:19Z")

</div>

give a MWE

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [May 18, 2024, 3:16pm UTC](https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432/3 "2024-05-18T15:16:58Z")

</div>

There’s a number of things that come into play here. The biggest is that in simple cases, the `getproperty` call will be inlined and turned into a simple `getfield` (when there isn’t a `getproperty` override for the type). Since the symbol is also `const` it will be possible for constant prop/semi-concrete eval to figure out what’s happening. That said, with sufficiently complex `getproperty` overloads it is very possible to make `foo.bar` uninferrable.

---

<div class="post-metadata">

**Author:** ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)\
**Post date:** [May 18, 2024, 3:48pm UTC](https://discourse.julialang.org/t/type-inference-and-the-dot-operator/114432/4 "2024-05-18T15:48:34Z")

</div>

That’s pretty much the conclusion I had come to from looking at some examples.

```julia
julia> struct foo{T}
         a::T
         b::Int
       end

julia> tt = foo(1.234, 5)
foo{Float64}(1.234, 5)

julia> @code_warntype tt.b
MethodInstance for getproperty(::foo{Float64}, ::Symbol)
  from getproperty(x, f::Symbol) @ Base Base.jl:37
Arguments
  #self#::Core.Const(getproperty)
  x::foo{Float64}
  f::Symbol
Body::Union{Float64, Int64}
1 ─ nothing
│ %2 = Base.getfield(x, f)::Union{Float64, Int64}
└── return %2

julia> function getb(f::foo)
         (; a, b) = f
         return b
       end
getb (generic function with 1 method)

julia> @code_warntype getb(tt)
MethodInstance for getb(::foo{Float64})
  from getb(f::foo) @ Main REPL[7]:1
Arguments
  #self#::Core.Const(getb)
  f::foo{Float64}
Locals
  b::Int64
  a::Float64
Body::Int64
1 ─ (a = Base.getproperty(f, :a))
│ (b = Base.getproperty(f, :b))
└── return b

```

If calls like `getproperty(f, :a)` occur inside another function further type inference can be carried out and the type reduced from a `Union` to a concrete type.

The fact the sufficiently complicated custom `getproperty` methods can interfere with this can change the balance of writing “getter” methods versus using properties. Often there are attributes of statistical models that are best evaluated on the fly from other information in the model struct and I have been adding cases in custom getproperty methods for these rather than defining (and documenting) extractor functions. I should reconsider that approach.
