# Why am I getting type instability?

**URL:** https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020
**Category:** General Usage
**Tags:** type-stability
**Created:** [November 9, 2023, 11:47pm UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020 "2023-11-09T23:47:33Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)
#### Post date: [November 9, 2023, 11:47pm UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020/1 "2023-11-09T23:47:33Z")

</div>

I’m trying to access linked entries in a sparse matrix where only the values change and thought it would be faster to save the locations of the values, but accessing them like this is much slower than just matrix indexing the sparse matrix and setting the values by hand. Inspecting with `@code_warntype` reveals a lot of red lines.

I made the type

```julia
mutable struct Observer{T,R}
    ref::R
    pair::Pair{Int32,Int32}
    nzidx1::Int32
    nzidx2::Int32
    val::T
end

```

Which I for example initialize as

```julia
sp # Some SparseMatrixCSC
ob = Observer(sp, 1=>2, 1, 101, sp.nzval[1])

@code_warntype ob.ref
MethodInstance for getproperty(::Observer{Float32, SparseMatrixCSC{Float32, Int32}}, ::Symbol)
  from getproperty(x, f::Symbol) @ Base Base.jl:37
Arguments
  #self#::Core.Const(getproperty)
  x::Observer{Float32, SparseMatrixCSC{Float32, Int32}}
  f::Symbol
Body::Any
1 ─ nothing
│ %2 = Base.getfield(x, f)::Any
└── return %2

```

Get field seems to be type instable?  
Then I’m trying to set them through a dict of these things, and `@code_warntype` reveals a lot of red.

```julia
function setval(ob::Observer, val)
    ob.ref.nzval[ob.nzidx1] = val
    ob.ref.nzval[ob.nzidx2] = val
end

struct ObserverList{A, B} <: AbstractDict{A, B}
    observers::Dict{A, B}
end

function setval(obs::ObserverList{A,Observer{T,R}}, val, pair) where {A, T, R<:SparseMatrixCSC{T}}
    if haskey(obs, pair)
        setval(obs[pair], val)
        return val
    end
    return val
end

@code_warntype setval(observers,1, 1=>2)
MethodInstance for setval(::ObserverList{Pair{Int32, Int32}, Observer{Float32}}, ::Int64, ::Pair{Int32, Int32})
  from setval(obs::ObserverList, val, pair) @ Main ~/Documents/GitHub/InteractiveRBM.jl/ObserverList.jl:41
Arguments
  #self#::Core.Const(setval)
  obs::ObserverList{Pair{Int32, Int32}, Observer{Float32}}
  val::Int64
  pair::Pair{Int32, Int32}
Locals
  observer::Observer{Float32}
Body::Union{Nothing, Int64}
1 ─ Core.NewvarNode(:(observer))
│ %2 = Main.haskey(obs, pair)::Bool
└── goto #3 if not %2
2 ─ (observer = Base.getindex(obs, pair))
│ %5 = Base.getproperty(observer, :ref)::SparseMatrixCSC
│ %6 = Base.getproperty(%5, :nzval)::Vector
│ %7 = Base.getproperty(observer, :nzidx1)::Int32
│ Base.setindex!(%6, val, %7)
│ %9 = Base.getproperty(observer, :ref)::SparseMatrixCSC
│ %10 = Base.getproperty(%9, :nzval)::Vector
│ %11 = Base.getproperty(observer, :nzidx2)::Int32
│ Base.setindex!(%10, val, %11)
└── return val
3 ─ return 

```

I’m open to this being a dumb idea, but I am genuinely a bit confused why the code ends up being type instable…

---

<div class="post-metadata">

### Author: ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)
#### Post date: [November 10, 2023, 1:31am UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020/2 "2023-11-10T01:31:40Z")

</div>

I can’t tell what’s up in the second case from my phone, but I believe the problem in the first code snippet is using a global variable.

Try adding `const` before `ob`, and I think that should fix it.

---

<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: [November 10, 2023, 7:53am UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020/3 "2023-11-10T07:53:53Z")

</div>

> [@f.ij](#):
>
> `@code_warntype ob.ref`

if you put this in a function it will be type stable. At top level, you’re calling `getproperty(ob, :ref)` and essentially `:ref` is just a value::Symbol, it is type unstable because you could have also put any `Symbol` in place of `:ref`.

```julia
julia> ob = Observer(sp, Int32(1)=>Int32(2), Int32(1), Int32(101), sp.nzval[1])
Observer{Float64, SparseMatrixCSC{Float64, Int64}}(sparse([1, 2, 3, 1, 2, 3, 1, 2, 3], [1, 1, 1, 2, 2, 2, 3, 3, 3], [0.509841105706249, 0.43349375105674504, 0.451087020785071, 0.48967587202828466, 0.4581567204538729, 0.0076022387129910385, 0.5606083626338405, 0.5221675969765492, 0.29058394151780376], 3, 3), 1 => 2, 1, 101, 0.509841105706249)

julia> f(x) = x.ref
f (generic function with 1 method)

julia> @code_warntype f(ob)
MethodInstance for f(::Observer{Float64, SparseMatrixCSC{Float64, Int64}})
  from f(x) @ Main REPL[12]:1
Arguments
  #self#::Core.Const(f)
  x::Observer{Float64, SparseMatrixCSC{Float64, Int64}}
Body::SparseMatrixCSC{Float64, Int64}
1 ─ %1 = Base.getproperty(x, :ref)::SparseMatrixCSC{Float64, Int64}
└── return %1

```

---

<div class="post-metadata">

### Author: ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)
#### Post date: [November 10, 2023, 12:50pm UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020/4 "2023-11-10T12:50:34Z")

</div>

> [@mrufsvold](#):
>
> I can’t tell what’s up in the second case from my phone, but I believe the problem in the first code snippet is using a global variable.
> 
> Try adding `const` before `ob`, and I think that should fix it.

I tried this but it does not. Putting it into another function like @jling suggested does work. Then still when accessing it through the Dict which is concretely types I’m still getting a lot of type instability. For example it can’t infer the type of the SparseMatrix even though everything should be concretely typed. I had thought that setting elements this way, e.g. doing a dict lookup and then having the exact indexes to update should’ve been quite a bit faster than doing a search within a column twice in a sparse matrix, but for my usecase (which admittedly is not a huge SparseMatrix) it seems ~3x as slow. I was thinking this might be due to the type instability, but I’m open to other suggestions.

---

<div class="post-metadata">

### Author: ![f.ij](https://avatars.discourse-cdn.com/v4/letter/f/8491ac/32.png) [@f.ij](https://discourse.julialang.org/u/f.ij)
#### Post date: [November 10, 2023, 1:58pm UTC](https://discourse.julialang.org/t/why-am-i-getting-type-instability/106020/5 "2023-11-10T13:58:46Z")

</div>

Okay, I found out what the problem was. This method is indeed a lot faster at setting elements in a sparsearray (~10x). The problem was I wrote a function setting up the dict from a SparseArray, and in the process didn’t realise that my object `observers` was of type `Observers{Pair{Int32,Int32}, Observer{Float32}}` which is not a concrete type. I think I made the false assumption that subtypes of DataTypes have to be concrete, but this is clearly false sinse `Observer{Float32}` is not a concrete type. I fixed this and now it’s blazing fast!
