# Closures over types are type unstable

**URL:** <https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337>\
**Category:** General Usage\
**Tags:** question, function, closure\
**Created:** [June 6, 2022, 6:43pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337 "2022-06-06T18:43:55Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tictaccat](https://avatars.discourse-cdn.com/v4/letter/t/9f8e36/32.png) [@tictaccat](https://discourse.julialang.org/u/tictaccat)\
**Post date:** [June 6, 2022, 6:43pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/1 "2022-06-06T18:43:56Z")

</div>

The closure returned by the following function

```julia
function f(x::AbstractArray)
           T = eltype(x)
           ax = axes(x)
           return () -> zeros(T, 1000)
end

```

is type unstable:

```julia
@code_warntype f(rand(3))()
MethodInstance for (::var"#41#42"{DataType})()
  from (::var"#41#42")() in Main at REPL[37]:4
Arguments
  #self#::var"#41#42"{DataType}
Body::Vector
1 ─ %1 = Core.getfield(#self#, :T)::DataType
│ %2 = Main.zeros(%1, 1000)::Vector
└── return %2

```

How can I modify it so that the function `f` returns a closure which is type stable?

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [June 6, 2022, 6:49pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/2 "2022-06-06T18:49:32Z")

</div>

This is an instance of the infamous closure bug

- manual section: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured)
- GitHub issue: [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)

If I understand correctly, the issue is that your closure views `T` as something “global” that could possibly change after its definition.  
Here is one way to solve it:

```julia
julia> function f(x::AbstractArray)
           T = eltype(x)
           ax = axes(x)
           g() = let T
               zeros(T, 1000)
           end
           return g
       end
f (generic function with 1 method)

julia> @code_warntype f(rand(3))()
MethodInstance for (::var"#g#11")()
  from (::var"#g#11")() in Main at /home/guillaume/Downloads/scratchpad.jl:4
Arguments
  #self#::Core.Const(var"#g#11"())
Locals
  T::Union{}
Body::Union{}
1 ─ Core.NewvarNode(:(T))
│ Main.zeros(T, 1000)
└── Core.Const(:(return %2))

```

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [June 6, 2022, 6:53pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/3 "2022-06-06T18:53:55Z")

</div>

PR: [Fix type instability of closures capturing types (2) by simeonschaub · Pull Request #40985 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/40985)

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [June 6, 2022, 6:54pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/4 "2022-06-06T18:54:58Z")

</div>

You could also do

```julia
julia> function f(x::AbstractArray{T}) where T
       ax = axes(x)
       return () -> zeros(T, 1000)
       end
f (generic function with 1 method)

julia> @code_warntype f(rand(3))()
MethodInstance for (::var"#1#2"{Float64})()
  from (::var"#1#2"{T})() where T in Main at REPL[1]:3
Static Parameters
  T = Float64
Arguments
  #self#::Core.Const(var"#1#2"{Float64}())
Body::Vector{Float64}
1 ─ %1 = Main.zeros($(Expr(:static_parameter, 1)), 1000)::Vector{Float64}
└── return %1

```

---

<div class="post-metadata">

**Author:** ![Christopher\_Fisher](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christopher_fisher/32/26132_2.png) [@Christopher\_Fisher](https://discourse.julialang.org/u/Christopher_Fisher)\
**Post date:** [June 6, 2022, 7:06pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/5 "2022-06-06T19:06:35Z")

</div>

Do you happen to know about the timeline for merging that PR?

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [June 6, 2022, 7:08pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/6 "2022-06-06T19:08:45Z")

</div>

That infers as `Union{}`, because it’ll throw rather than return. But replacing `zeros(T, 1000)` with `zeros(eltype(T), 1000)` does infer on at least Julia 1.7, 1.8 and master.

I don’t know a timeline for merging the PR.

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [June 6, 2022, 7:33pm UTC](https://discourse.julialang.org/t/closures-over-types-are-type-unstable/82337/7 "2022-06-06T19:33:00Z")

</div>

Whoops, I misread `eltype` as `typeof`.

I edited my previous post to have `function f(x::AbstractArray{T}) where T`, and now it infers to `Vector{Float64}` (and does not throw).
