# Type issue with captured variables -\> let workaround failed

**URL:** https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661
**Category:** General Usage
**Tags:** fftw, performance, closure
**Created:** [August 12, 2022, 12:00pm UTC](https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661 "2022-08-12T12:00:00Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [August 12, 2022, 12:00pm UTC](https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661/1 "2022-08-12T12:00:00Z")

</div>

Hi!

I’m aware of [#15276](https://github.com/JuliaLang/julia/issues/15276) but today I encountered an issue in the proposed [workaround](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured).

```julia
using FFTW

function f(x)
    p = plan_fft(x)
    x_ft = p * x 

   # given workaround in performance tips
    g = let p = p 
            x_ft = x_ft
        a -> (p*a) * x_ft
    end 

    return g
end

function f2(x)
    p = plan_fft(x)
    x_ft = p * x 

    # difference is a local name which is different to the original x_ft
    g = let p = p 
            x_ft2 = x_ft
        a -> (p*a) * x_ft2
    end 

    return g
end

```

The first function struggles with boxing, the second not:

```julia
julia> g = f(x)
#9 (generic function with 1 method)

julia> @code_warntype g(x)
MethodInstance for (::var"#9#10"{FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}})(::Matrix{Float64})
  from (::var"#9#10")(a) in Main at /home/fxw/.julia/dev/FourierTools.jl/lel.jl:11
Arguments
  #self#::var"#9#10"{FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}}
  a::Matrix{Float64}
Locals
  x_ft::Union{}
Body::Any
1 ─ %1 = Core.getfield(#self#, Symbol("#66#p"))::FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}
│ %2 = (%1 * a)::Matrix{ComplexF64}
│ %3 = Core.getfield(#self#, :x_ft)::Core.Box
│ %4 = Core.isdefined(%3, :contents)::Bool
└── goto #3 if not %4
2 ─ goto #4
3 ─ Core.NewvarNode(:(x_ft))
└── x_ft
4 ┄ %9 = Core.getfield(%3, :contents)::Any
│ %10 = (%2 * %9)::Any
└── return %10

julia> g2 = f2(x)
#15 (generic function with 1 method)

julia> @code_warntype g2(x)
MethodInstance for (::var"#15#16"{Matrix{ComplexF64}, FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}})(::Matrix{Float64})
  from (::var"#15#16")(a) in Main at /home/fxw/.julia/dev/FourierTools.jl/lel.jl:25
Arguments
  #self#::var"#15#16"{Matrix{ComplexF64}, FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}}
  a::Matrix{Float64}
Body::Matrix{ComplexF64}
1 ─ %1 = Core.getfield(#self#, Symbol("#76#p"))::FFTW.cFFTWPlan{ComplexF64, -1, false, 2, UnitRange{Int64}}
│ %2 = (%1 * a)::Matrix{ComplexF64}
│ %3 = Core.getfield(#self#, :x_ft2)::Matrix{ComplexF64}
│ %4 = (%2 * %3)::Matrix{ComplexF64}
└── return %4

```

What is the reason for this behavior? It is definitely related to the FFTW planning or at least to the `FFTW.cFFTWPlan` (which is an own type).

Best,

Felix

---

<div class="post-metadata">

### Author: ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)
#### Post date: [August 12, 2022, 12:18pm UTC](https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661/2 "2022-08-12T12:18:47Z")

</div>

Does adding a comma at the end of `let p = p` help? Currently, `x_ft = x_ft` in `f(x)` is the first statement _inside_ the `let` block, not part of its initial comma-separated assignment list.

I don’t understand what `let` does - or scoping in general - well enough to know _why_ that makes a difference. But in my case, it makes both functions have the same `@code_warntype` output with no type issues.

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [August 12, 2022, 12:20pm UTC](https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661/3 "2022-08-12T12:20:52Z")

</div>

You’re totally right!  
I totally wasn’t aware of that, but it totally makes sense (need urgently fix a few dozens lines in my code 😂)

---

<div class="post-metadata">

### Author: ![ikirill](https://avatars.discourse-cdn.com/v4/letter/i/43a26b/32.png) [@ikirill](https://discourse.julialang.org/u/ikirill)
#### Post date: [August 13, 2022, 6:59am UTC](https://discourse.julialang.org/t/type-issue-with-captured-variables-let-workaround-failed/85661/4 "2022-08-13T06:59:30Z")

</div>

You can look at how Julia parses the blocks:

```julia

julia> using Base.Meta

julia> @dump let a=a
       b=b
       1
       end
Expr
  head: Symbol let
  args: Array{Any}((2,))
    1: Expr
      head: Symbol =
      args: Array{Any}((2,))
        1: Symbol a
        2: Symbol a
    2: Expr
      head: Symbol block
      args: Array{Any}((4,))
        1: LineNumberNode
          line: Int64 2
          file: Symbol REPL[2]
        2: Expr
          head: Symbol =
          args: Array{Any}((2,))
            1: Symbol b
            2: Symbol b
        3: LineNumberNode
          line: Int64 3
          file: Symbol REPL[2]
        4: Int64 1

julia> @dump let a=a, b=b
       1
       end
Expr
  head: Symbol let
  args: Array{Any}((2,))
    1: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: Expr
          head: Symbol =
          args: Array{Any}((2,))
            1: Symbol a
            2: Symbol a
        2: Expr
          head: Symbol =
          args: Array{Any}((2,))
            1: Symbol b
            2: Symbol b
    2: Expr
      head: Symbol block
      args: Array{Any}((2,))
        1: LineNumberNode
          line: Int64 2
          file: Symbol REPL[3]
        2: Int64 1

```

maybe then it’s easier to see what’s wrong. `@dump` helps when the syntax looks ambiguous.
