I know that getproperty
is normally not type stable. But I had the mental model that getproperty
on a named tuple is magically type stable somehow. And I had the same belief for getindex
on a tuple or named tuple. However, my mental model appears to be wrong, at least in the global scope:
julia> t = (1, 2.0)
(1, 2.0)
julia> @code_warntype t[1]
Variables
#self#::Core.Const(getindex)
t::Tuple{Int64, Float64}
i::Int64
Body::Union{Float64, Int64}
1 ─ nothing
│ %2 = Base.getfield(t, i, $(Expr(:boundscheck)))::Union{Float64, Int64}
└── return %2
Taken by itself, that seems understandable to me. What I don’t quite get is that if I merely wrap t[1]
in a function, the type instability goes away:
julia> foo(t) = t[1];
julia> @code_warntype foo(t)
Variables
#self#::Core.Const(foo)
t::Tuple{Int64, Float64}
Body::Int64
1 ─ %1 = Base.getindex(t, 1)::Int64
└── return %1
Can anyone explain why t[1]
in global scope is not type stable but foo(t)
is type stable? My only guess is that when t[1]
is in a local scope instead of global scope, the compiler can make more guarantees about the type of t[1]
, but that’s a hand-wavy argument.