# Type instability of nested function

**URL:** <https://discourse.julialang.org/t/type-instability-of-nested-function/57007>\
**Category:** New to Julia\
**Created:** [March 12, 2021, 9:12am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007 "2021-03-12T09:12:00Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jae-Mo\_Lihm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jae-mo_lihm/32/20145_2.png) [@Jae-Mo\_Lihm](https://discourse.julialang.org/u/Jae-Mo_Lihm)\
**Post date:** [March 12, 2021, 9:12am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/1 "2021-03-12T09:12:00Z")

</div>

I have the following function, and it has a type instability (`Core.Box`).

In the real code, I use `f` as an argument of another function which calls `f` multiple times (e.g. bisection to solve `f(x)=0`).

How can I make this function type stable?

```julia
function test(a)
    b = a
    if a < 0
        b = -a
    end
    f(x) = x + b
    f(10)
end

```

```julia
julia> @code_warntype test(1)
Variables
  #self#::Core.Compiler.Const(test, false)
  a::Int64
  b::Core.Box
  f::var"#f#61"

Body::Any
1 ─ (b = Core.Box())
│ Core.NewvarNode(:(f))
│ %3 = a::Int64
│ Core.setfield!(b, :contents, %3)
│ %5 = (a < 0)::Bool
└── goto #3 if not %5
2 ─ %7 = -a::Int64
└── Core.setfield!(b, :contents, %7)
3 ┄ (f = %new(Main.:(var"#f#61"), b))
│ %10 = (f)(10)::Any
└── return %10

```

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [March 12, 2021, 9:17am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/2 "2021-03-12T09:17:12Z")

</div>

I guess you hit [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)

Current solution is just to put your closure in `let` block

```julia
function test(a)
    b = a
    if a < 0
        b = -a
    end
    let b = b
        f(x) = x + b
        f(10)
    end
end

julia> @code_warntype test(1)
MethodInstance for test(::Int64)
  from test(a) in Main at REPL[3]:1
Arguments
  #self#::Core.Const(test)
  a::Int64
Locals
  b@_3::Int64
  f::var"#f#4"{Int64}
  b@_5::Int64
Body::Int64

```

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [March 12, 2021, 10:13am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/3 "2021-03-12T10:13:14Z")

</div>

The function body is probably a dummy, but it still might be helpful: conditionals blocks in Julia are expressions, not statements. So, you may write

```julia
function test(a)
    b = if a >= 0
        a
    else
        -a
    end
    f(x) = x + b
    f(10)
end

```

If you have to have a mutable variable captured, use a reference to avoid re-binding:

```julia
function test_ref(a)
    b = Ref(a)
    if a < 0
        b[] = -a
    end
    f(x) = x + b[]
    f(10)
end

```

---

<div class="post-metadata">

**Author:** ![Shuhua](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shuhua/32/27618_2.png) [@Shuhua](https://discourse.julialang.org/u/Shuhua)\
**Post date:** [March 12, 2021, 10:21am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/4 "2021-03-12T10:21:14Z")

</div>

By the way, what does `(b = Core.Box())` mean in the original example? Is it due to capturing? 😉

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [March 12, 2021, 10:59am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/5 "2021-03-12T10:59:20Z")

</div>

I am not an expert, but I think you are right, capturing is the most reasonable explanation. IIRC it is a scope problem: variable `b` is changed outside of closure, so compiler puts it in a `Box` to trace these changes (presumably it is the same trick as `Ref`). When new scope is introduced with the help of the `let` block, compiler is happy and not boxing anything. But I may be wrong, so take it with a grain of salt.

---

<div class="post-metadata">

**Author:** ![Shuhua](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shuhua/32/27618_2.png) [@Shuhua](https://discourse.julialang.org/u/Shuhua)\
**Post date:** [March 12, 2021, 11:13am UTC](https://discourse.julialang.org/t/type-instability-of-nested-function/57007/6 "2021-03-12T11:13:31Z")

</div>

> [@Skoffer](#):
>
> When new scope is introduced with the help of the `let` block, compiler is happy and not boxing anything

The `b` in the `let` scope is never changed. Thus there is no boxing, right? It is the first time I knew that closure capturing can lead to type instability.
