# Type stability of indexing a tuple in local scope vs global scope

**URL:** <https://discourse.julialang.org/t/type-stability-of-indexing-a-tuple-in-local-scope-vs-global-scope/70007>\
**Category:** General Usage\
**Created:** [October 18, 2021, 9:47pm UTC](https://discourse.julialang.org/t/type-stability-of-indexing-a-tuple-in-local-scope-vs-global-scope/70007 "2021-10-18T21:47:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 18, 2021, 9:47pm UTC](https://discourse.julialang.org/t/type-stability-of-indexing-a-tuple-in-local-scope-vs-global-scope/70007/1 "2021-10-18T21:47:14Z")

</div>

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
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
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.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [October 18, 2021, 11:46pm UTC](https://discourse.julialang.org/t/type-stability-of-indexing-a-tuple-in-local-scope-vs-global-scope/70007/2 "2021-10-18T23:46:11Z")

</div>

The behavior of `@code_warntype` makes a bit more sense if you look at what it’s actually doing:

```julia
julia> @macroexpand @code_warntype t[1]
:(InteractiveUtils.code_warntype(getindex, (Base.typesof)(t, 1)))

julia> Base.typesof(t, 1)
Tuple{Tuple{Int64, Float64}, Int64}

```

So `@code_warntype` is just calling the regular function `code_warntype` with the types of `t` and `1`, which are `Tuple{Int64, Float64}` and `Int64`, respectively.

That means `code_warntype` has only access to the _type_ of `1`, not the constant value. There’s no way it can possibly return anything more specific than a `Union` because, just from that information, there’s no way to know if you asked for `t[1]` or `t[2]`.

Once you’ve hard-coded the index 1 in a function, though, the compiler can be even smarter and do some constant propagation to figure out the result type. When you do: `@code_warntype foo(t)`, there actually is enough information from just the type of `t` to infer the result of `foo` because of the literal `t[1]` in the definition of `foo`.

Being in a function doesn’t really matter–we can show that even in a function `@code_warntype`’s behavior doesn’t change at all:

```julia
julia> function bar(t)
         @code_warntype t[1]
         t[1]
       end
bar (generic function with 1 method)

julia> bar(t)
Variables
  #self#::Core.Const(getindex)
  t::Tuple{Int64, Float64}
  i::Int64

Body::Union{Float64, Int64}

```

There’s no difference because `@code_warntype` is just calling `code_warntype(getindex, typesof(t, 1))` just as before.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 19, 2021, 1:34pm UTC](https://discourse.julialang.org/t/type-stability-of-indexing-a-tuple-in-local-scope-vs-global-scope/70007/3 "2021-10-19T13:34:21Z")

</div>

That makes sense. Thanks for clearing that up!
