Type instabilities when dealing with structs and Ref

Hello,

I’m facing type instabilities with a struct containing a Ref value. Here I show a minimal example

struct Prova{T1<:Integer}
    a::Ref{T1}
    function Prova(a::T1) where {T1}
        new{T1}(Ref(a))
    end
end

function function_test(p::Prova)
    c = p.a[]
    if !iszero(c)
        return c
    end
    return 46
end

p = Prova(42)
Prova{Int64}(Base.RefValue{Int64}(42))

But if I test the type instabilities I get

@code_warntype function_test(p)
MethodInstance for function_test(::Prova{Int64})
  from function_test(p::Prova) @ Main Untitled-1:111
Arguments
  #self#::Core.Const(function_test)
  p::Prova{Int64}
Locals
  c::Any
Body::Any
1 ─ %1 = Base.getproperty(p, :a)::Ref{Int64}
│        (c = Base.getindex(%1))
│   %3 = Main.iszero(c)::Any
│   %4 = !%3::Any
└──      goto #3 if not %4
2 ─      return c
3 ─      return 46

Ref is an abstract type. You need Base.RefValue in your struct.

julia> typeof(Ref(42))
Base.RefValue{Int64}

But how to solve it then?

struct Prova{T1<:Integer}
    a::Base.RefValue{T1}
    function Prova(a::T1) where {T1}
        new{T1}(Ref(a))
    end
end
1 Like

Perhaps a nicer approach:

julia> struct S{T<:Ref{<:Integer}}
           a::T
       end

julia> f(x) = S(Ref(x))
f (generic function with 1 method)

julia> f(42)
S{Base.RefValue{Int64}}(Base.RefValue{Int64}(42))
3 Likes