# Type instability of reference struct member

**URL:** <https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111>\
**Category:** General Usage\
**Created:** [June 22, 2025, 2:49pm UTC](https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111 "2025-06-22T14:49:15Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![atteson](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@atteson](https://discourse.julialang.org/u/atteson)\
**Post date:** [June 22, 2025, 2:49pm UTC](https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111/1 "2025-06-22T14:49:15Z")

</div>

Why is the first function below type stable and the second not?

```julia
test( rv::Ref{V} ) where V = rv[]
@code_warntype test( Ref(0x1) )

struct T{V}
    root::Ref{V}
end
t = T( Ref(0x1) )
test( t::T{V} ) where V = t.root[]
@code_warntype test( t )

```

I’m using julia 1.11.5.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [June 22, 2025, 3:03pm UTC](https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111/2 "2025-06-22T15:03:15Z")

</div>

because `Ref` is an abstract type:

```julia
julia> isabstracttype(Ref)
true

julia> isabstracttype(Base.RefValue)
false

```

you want this:

```julia
julia> struct T{V}
           root::Base.RefValue{V}
       end
       t = T( Ref(0x1) )
       test( t::T{V} ) where V = t.root[]
       @code_warntype test( t )

```

or

```julia
julia> struct T{R<:Ref}
           root::R
       end
       t = T( Ref(0x1) )
       test( t ) = t.root[]
       @code_warntype test( t )

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [June 22, 2025, 4:13pm UTC](https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111/3 "2025-06-22T16:13:27Z")

</div>

`Ref` being an abstract type is not enough to explain the difference. The crucial bit that’s missing is that Julia will specialize function calls to `test(rv::Ref{V})` according to the _actual type_ of the object being passed in. So when you pass in a `Base.RefValue`, `test` is compiled for that specific type, which means that there is no type instability in the first place.

In the case of your `struct` though, Julia doesn’t have that information available - when the `test` function is compiled for the struct argument, all that is known about the `root` field is the abstract type of the field, not the type of the actual object that’s stored there. Hence, the compiler can’t assume anything more specific and inserts a dynamic dispatch. After all, any object with a type that’s a subtype of `Ref` may be stored at that field, not just `Base.RefValue`.

* * *

The fact that this confusion comes up in the first place is quite unfortunate. `Ref` is an abstract type, documented to always refer to valid, julia-allocated memory. It’s also the supertype of `Ptr`, which may be coming from outside of Julia! This doesn’t really make much sense.. See [`Ptr` doesn't observe the supertype semantics of `Ref` · Issue #49004 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/49004) where this is tracked upstream.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [June 22, 2025, 7:53pm UTC](https://discourse.julialang.org/t/type-instability-of-reference-struct-member/130111/4 "2025-06-22T19:53:31Z")

</div>

see also

> <https://github.com/JuliaLang/julia/issues/38133#issuecomment-713948596>
>
> \`\`\`
> julia\> struct Foo
> i::Ref{Int}
> end
> 
> julia\> f = Foo(Ref…(0))
> Foo(Base.RefValue{Int64}(0))
> 
> julia\> g(x) = x.i\[\]
> g (generic function with 1 method)
> 
> julia\> @code\_warntype g(f)
> Variables
> #self#::Core.Const(g)
> x::Foo
> 
> Body::Any
> 1 ─ %1 = Base.getproperty(x, :i)::Ref{Int64}
> │ %2 = Base.getindex(%1)::Any
> └── return %2
> 
> julia\> versioninfo()
> Julia Version 1.6.0-DEV.1227
> Commit 86bbe0941c (2020-10-15 00:29 UTC)
> \`\`\`
> I thought this would infer the return type as \`Int\`, but it only manages \`Any\`. Am I doing something wrong, or is this expected? Is there a situation where the dereference can return something other than \`Int\`?
