# Why is this code not type stable?

**URL:** <https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527>\
**Category:** General Usage\
**Tags:** question\
**Created:** [January 25, 2023, 6:42pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527 "2023-01-25T18:42:00Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 6:42pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/1 "2023-01-25T18:42:00Z")

</div>

```julia
inner(pc) = sum(pc)
outer(pc,σ) = prod(pc,σ)

tst = let
    pc = rand(3,10)
    σ = 2.0
    
    tst() = losses = outer(inner(pc), σ)
end

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 6:49pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/2 "2023-01-25T18:49:39Z")

</div>

> [@prittjam](#):
>
> ```julia
> tst = let
> pc = rand(3,10)
> σ = 2.0
>     
> tst() = losses = outer(inner(pc), σ)
> end
> 
> ```

What do you want to achieve here?

Isn’t just

```julia
tst(pc,σ) = outer(inner(pc),σ)

tst(rand(3,10), 2.0)) 

```

what you want there?

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:06pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/3 "2023-01-25T19:06:24Z")

</div>

I’m just trying to come up with a contrived example that illustrates the problem in much more complicated code. I don’t understand the type instability with closures. I will see if i can construct a closer example.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:09pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/4 "2023-01-25T19:09:51Z")

</div>

If the variable that is closed-over is a global variable, not constant and not typed, then the closure will be type unstable. For example:

```julia
julia> a = 1.0
1.0

julia> f(x) = x - a
f (generic function with 1 method)

julia> @code_warntype(f(1.0))
MethodInstance for f(::Float64)
  from f(x) in Main at REPL[5]:1
Arguments
  #self#::Core.Const(f)
  x::Float64
Body::Any
1 ─ %1 = (x - Main.a)::Any
└── return %1

```

That’s type unstable because the type of `a` cannot be known. Also there is [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276), which is a long standing difficulty on using closures in many contexts.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:33pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/5 "2023-01-25T19:33:51Z")

</div>

This is type unstable,

```julia
    pc = problem.cspond
    σ = 4.0
# pc = pc, σ = σ
    calc_loss = let
        losses = Vector{Float64}(undef, length(pc))
        calc_loss(F::FundamentalMatrix)::Vector{Float64} = losses .= cauchy_ρ.(fund_mat_signed_sampson_dist.(pc, Ref(F)), σ)
    end

```

while this is type stable,

```julia
    pc = problem.cspond
    σ = 4.0
    calc_loss = let pc = pc, σ = σ
        losses = Vector{Float64}(undef, length(pc))
        calc_loss(F::FundamentalMatrix)::Vector{Float64} = losses .= cauchy_ρ.(fund_mat_signed_sampson_dist.(pc, Ref(F)), σ)
    end

```

I guess it’s related to the bug you referenced. I tried to use FastClosures, but I could not understand how to use it in this context.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:37pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/6 "2023-01-25T19:37:13Z")

</div>

If you are running that in the global scope, it will be type unstable just because `pc` and `sigma` are non-constant globals in the first case, and aren’t in the second.

Otherwise it is probably related to that bug.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:37pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/7 "2023-01-25T19:37:47Z")

</div>

no, pc and sigma are declared in the context of a function. it was a bit hard to construct a minimal working example here.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:38pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/8 "2023-01-25T19:38:27Z")

</div>

Then its the bug. I think using the assignments on the let are effectively the way to handle that.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:39pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/9 "2023-01-25T19:39:04Z")

</div>

I don’t understand why that fixes things. But also isn’t there a fastclosure package that is supposed to fix this? how do you use the macro?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:40pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/10 "2023-01-25T19:40:21Z")

</div>

I think there it would be just:

```julia
@closure calc_loss(F::FundamentalMatrix)::Vector{Float64} = losses .= cauchy_ρ.(fund_mat_signed_sampson_dist.(pc, Ref(F)), σ)

```

(replacing the let block, with the definition of losses, pc and sigma outside there.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:40pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/11 "2023-01-25T19:40:56Z")

</div>

I think i tried that and there was some compile error. Ok, I will take a look again. This bug is a big problem because optimization code often needs closure for reasonable syntax.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:43pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/12 "2023-01-25T19:43:07Z")

</div>

The problem is more when modifying the closed over variables. In your case the `losses` variable is being closed over and modified. Maybe it is more clear if you define it inside the `calc_loss` function, or if you pass it as a parameter as well.

(but yes, it is an annoying bug)

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 7:45pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/13 "2023-01-25T19:45:40Z")

</div>

if I make losses an lvalue, is it possible to avoid a temporary array created inside calc\_loss, in other words,

```julia
losses .= calc_loss(...)

```

I get a bit confused if the compiler can optimize this.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2023, 7:52pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/14 "2023-01-25T19:52:02Z")

</div>

only if losses is a small static array, otherwise it can’t.

The other way (which I like most, is make `calc_losses` a callable object that carries the buffer. Something like:

```julia
julia> struct CalcLosses
           losses::Vector{Float64}
           a::Float64
       end

julia> (c::CalcLosses)(x::Vector{Float64}) = c.losses .= c.a .* x

julia> calc_losses = CalcLosses(ones(10), 2.0)
CalcLosses([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 2.0)

julia> calc_losses(rand(10))
10-element Vector{Float64}:
 0.48654014606839024
 0.7925405464740596
 1.0971990327794896
 1.1542839828629714
 0.29858374238632046
 0.029375859407316796
 1.6187913231998186
 0.056574918959434894
 1.0338038499413729
 1.2413140671199132

```

I don’t know if every type of optimization interface can handle that, though.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 8:07pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/15 "2023-01-25T20:07:18Z")

</div>

```julia
(c::CalcLosses)(x::Vector{Float64}) = c.losses .= c.a .* x

```

you’ve lost me here 🙂 Can you explain this syntax?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [January 25, 2023, 8:10pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/16 "2023-01-25T20:10:41Z")

</div>

> [@prittjam](#):
>
> you’ve lost me here 🙂 Can you explain this syntax?

Functions in julia aren’t the only things that can have methods. In fact, functions are just a special case of something called “callable structs”. The idea here, is that you can treat the struct `CalcLosses` as a function itself, but that function stores data it can reference.

So when they write

```julia
(c::CalcLosses)(x::Vector{Float64}) = c.losses .= c.a .* x

```

it’s saying that for any `c` whose type is `CalcLosses`, you can write `c(x)` where `x` is of type `Vector{Float64}` and it will compute `c.losses .= c.a .* x`.

---

<div class="post-metadata">

**Author:** ![prittjam](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/prittjam/32/21267_2.png) [@prittjam](https://discourse.julialang.org/u/prittjam)\
**Post date:** [January 25, 2023, 8:19pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/17 "2023-01-25T20:19:00Z")

</div>

But this functionality seems very similar to what can be achieved with closures. Besides avoiding the compiler bug or limitation, what is the advantage of this construction?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [January 25, 2023, 8:31pm UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/18 "2023-01-25T20:31:15Z")

</div>

I didn’t say it was different. In fact, this is exactly how closures work. The problem is just that closures can’t assume that various things are type stable, so you essentially end up with a struct that looks like

```julia
struct CalcLosses
    losses::Any
    a::Any
end

```

or something if it can’t assume that `losses` and `a` dont’ change type.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 26, 2023, 1:20am UTC](https://discourse.julialang.org/t/why-is-this-code-not-type-stable/93527/19 "2023-01-26T01:20:38Z")

</div>

> [@prittjam](#):
>
> if I make losses an lvalue … in other words,
> 
> ```julia
> losses .= calc_loss(...)
> 
> ```

Counterintuitively, `losses` is an rvalue here because this expression lowers to a call to `Base.materialize!(losses, ...)`. You can confirm this like so:

```julia
julia> _ = [1,2,3];

julia> _ .= [1,2,3];
ERROR: syntax: all-underscore identifier used as rvalue

```

It’s similar to how in the expression `x[1:2] = 3:4`, `x` is an rvalue because the expression is lowered to `setindex!(x, 3:4, 1:2)`. Not to worry, this is a good thing; because it’s an rvalue, the identifier is not reassigned.

However, from your description above, the actual type instability is likely occuring because `pc` and/or `σ` are assigned to more than once in the parent scope, making it so that `calc_loss` doesn’t know what value to assume when it’s called, so it boxes them. This is why the `let` block trick works: it captures a snapshot of their values and makes it so the closure can access only the value at that specific point.
