# Can I use a closure, and if yes how?

**URL:** https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857
**Category:** General Usage
**Tags:** question, closure
**Created:** [May 5, 2024, 11:08am UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857 "2024-05-05T11:08:28Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 5, 2024, 11:08am UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/1 "2024-05-05T11:08:28Z")

</div>

I have the following code:

```julia
using ControlPlots
using KiteModels, KitePodModels, KiteUtils

set = deepcopy(se())
kcu::KCU = KCU(set)
kps4::KPS4 = KPS4(kcu)

include("../examples/plot2d.jl")

reltime = 0.0
integrator = KiteModels.init_sim!(kps4, stiffness_factor=0.5)

lines, sc, txt = nothing, nothing, nothing
lines, sc, txt = plot2d(kps4.pos, reltime; zoom=true, front=false, segments=set.segments, lines, sc, txt)
nothing

```

The included file looks like this:

```julia
function plot2d(pos, reltime=0.0; zoom=true, front=false, segments=6, fig="", lines, sc, txt)
    x = Float64[] 
    z = Float64[]
    for i in eachindex(pos)
        if front
            push!(x, pos[i][2])
        else
            push!(x, pos[i][1])
        end
        push!(z, pos[i][3])
    end
    x_max = maximum(x)
    z_max = maximum(z)
    xlabel = "x [m]"
    if front xlabel = "y [m]" end
    if isnothing(lines)
        if fig != ""
            plt.figure(fig)
        end
        lines=[]
        line, = plt.plot(x,z; linewidth="1")
        push!(lines, line)
        sc = plt.scatter(x, z; s=25, color="red") 
        if zoom
            txt = plt.annotate("t=$(round(reltime,digits=1)) s",  
                xy=(x_max, z_max+4.7), fontsize = 14)
            plt.xlim(x_max-15.0, x_max+20)
            plt.ylim(z_max-15.0, z_max+8)
        else
            txt = plt.annotate("t=$(round(reltime,digits=1)) s",  
            xy=(x_max, z_max+8.0), fontsize = 14)
            plt.xlim(0, x_max+20)
            plt.ylim(0, z_max+20)
        end
        if length(pos) > segments+1
            s=segments
            line, = plt.plot([x[s+1],x[s+4]],[z[s+1],z[s+4]], linewidth="1"); push!(lines, line) # S6
            line, = plt.plot([x[s+2],x[s+5]],[z[s+2],z[s+5]], linewidth="1"); push!(lines, line) # S8
            line, = plt.plot([x[s+3],x[s+5]],[z[s+3],z[s+5]], linewidth="1"); push!(lines, line) # S7
            line, = plt.plot([x[s+2],x[s+4]],[z[s+2],z[s+4]], linewidth="1"); push!(lines, line) # S2
            line, = plt.plot([x[s+1],x[s+5]],[z[s+1],z[s+5]], linewidth="1"); push!(lines, line) # S5
        end
        plt.xlabel(xlabel, fontsize=14)
        plt.ylabel("z [m]", fontsize=14)
        plt.grid(true)
        plt.grid(which="major", color="#DDDDDD")
    else
        lines[1].set_xdata(x)
        lines[1].set_ydata(z)
        if length(pos) > segments+1
            s=segments
            lines[2].set_xdata([x[s+1],x[s+4]]) # S6
            lines[2].set_ydata([z[s+1],z[s+4]]) # S6
            lines[3].set_xdata([x[s+2],x[s+5]]) # S8
            lines[3].set_ydata([z[s+2],z[s+5]]) # S8
            lines[4].set_xdata([x[s+3],x[s+5]]) # S7
            lines[4].set_ydata([z[s+3],z[s+5]]) # S7
            lines[5].set_xdata([x[s+2],x[s+4]]) # S2
            lines[5].set_ydata([z[s+2],z[s+4]]) # S2
            lines[6].set_xdata([x[s+1],x[s+5]]) # S5
            lines[6].set_ydata([z[s+1],z[s+5]]) # S5
        end
        sc.set_offsets(hcat(x,z))
        txt.set_text("t=$(round(reltime,digits=1)) s")
        plt.gcf().canvas.draw()
    end
    sleep(0.01)
    lines, sc, txt
end

```

When the function plot2d is called the first time, a plot is created. Any further call results in just moving the line and updating the text, but not creating anything new.

In the end we get a 2D movie…

Now my question:  
I create the three variables

```julia
lines, sc, txt = nothing, nothing, nothing 

```

and also return them from the function to keep the state…  
Normally the function is called in a loop, see for example: [KiteModels.jl/examples/reel\_out\_4p.jl at e3142cc7e3a6473f23a465f4d71cc80e3eebc4ed · ufechner7/KiteModels.jl · GitHub](https://github.com/ufechner7/KiteModels.jl/blob/e3142cc7e3a6473f23a465f4d71cc80e3eebc4ed/examples/reel_out_4p.jl#L37C1-L65C4)

Is there a way to create a closure such that I do not have to pass or return these variables?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [May 5, 2024, 4:42pm UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/2 "2024-05-05T16:42:23Z")

</div>

For the code you linked, something like this should work:

```julia
# Instead of lines, sc, txt = nothing, nothing, nothing
# define a closure over that state
plotter = let lines = nothing, sc = nothing, txt = nothing # Note: Must all be on same line as let!
              function(x, y; kwargs...)
                  lines, sc, txt = plot2d(x, y; lines, sc, txt, kwargs...)
              end
          end
# ...
# Now in the loop call plotter instead of plot2d
if mod(i, 5) == 0
   plotter(kps4.pos, reltime; zoom=ZOOM, front=FRONT_VIEW, 
                              segments=set.segments, fig="side_view")            
end

```

This “let-over-lambda” construction is a general idiom for creating stateful closures and broadly applicable, i.e., I did not check what `plot2d` actually does.

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 5, 2024, 5:12pm UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/3 "2024-05-05T17:12:34Z")

</div>

This actually works, thanks a lot!

```julia
function plot2d_(pos, reltime; zoom=true, front=false, segments=6, fig="", lines, sc, txt)
    x = Float64[] 
    z = Float64[]
    for i in eachindex(pos)
        if front
            push!(x, pos[i][2])
        else
            push!(x, pos[i][1])
        end
        push!(z, pos[i][3])
    end
    x_max = maximum(x)
    z_max = maximum(z)
    xlabel = "x [m]"
    if front xlabel = "y [m]" end
    if isnothing(lines)
        if fig != ""
            plt.figure(fig)
        end
        lines=[]
        line, = plt.plot(x,z; linewidth="1")
        push!(lines, line)
        sc = plt.scatter(x, z; s=25, color="red") 
        if zoom
            txt = plt.annotate("t=$(round(reltime,digits=1)) s",  
                xy=(x_max, z_max+4.7), fontsize = 14)
            plt.xlim(x_max-15.0, x_max+20)
            plt.ylim(z_max-15.0, z_max+8)
        else
            txt = plt.annotate("t=$(round(reltime,digits=1)) s",  
            xy=(x_max, z_max+8.0), fontsize = 14)
            plt.xlim(0, x_max+20)
            plt.ylim(0, z_max+20)
        end
        if length(pos) > segments+1
            s=segments
            line, = plt.plot([x[s+1],x[s+4]],[z[s+1],z[s+4]], linewidth="1"); push!(lines, line) # S6
            line, = plt.plot([x[s+2],x[s+5]],[z[s+2],z[s+5]], linewidth="1"); push!(lines, line) # S8
            line, = plt.plot([x[s+3],x[s+5]],[z[s+3],z[s+5]], linewidth="1"); push!(lines, line) # S7
            line, = plt.plot([x[s+2],x[s+4]],[z[s+2],z[s+4]], linewidth="1"); push!(lines, line) # S2
            line, = plt.plot([x[s+1],x[s+5]],[z[s+1],z[s+5]], linewidth="1"); push!(lines, line) # S5
        end
        plt.xlabel(xlabel, fontsize=14)
        plt.ylabel("z [m]", fontsize=14)
        plt.grid(true)
        plt.grid(which="major", color="#DDDDDD")
    else
        lines[1].set_xdata(x)
        lines[1].set_ydata(z)
        if length(pos) > segments+1
            s=segments
            lines[2].set_xdata([x[s+1],x[s+4]]) # S6
            lines[2].set_ydata([z[s+1],z[s+4]]) # S6
            lines[3].set_xdata([x[s+2],x[s+5]]) # S8
            lines[3].set_ydata([z[s+2],z[s+5]]) # S8
            lines[4].set_xdata([x[s+3],x[s+5]]) # S7
            lines[4].set_ydata([z[s+3],z[s+5]]) # S7
            lines[5].set_xdata([x[s+2],x[s+4]]) # S2
            lines[5].set_ydata([z[s+2],z[s+4]]) # S2
            lines[6].set_xdata([x[s+1],x[s+5]]) # S5
            lines[6].set_ydata([z[s+1],z[s+5]]) # S5
        end
        sc.set_offsets(hcat(x,z))
        txt.set_text("t=$(round(reltime,digits=1)) s")
        plt.gcf().canvas.draw()
    end
    sleep(0.01)
    lines, sc, txt
end

plot2d = let lines = nothing, sc = nothing, txt = nothing # Note: Must all be on same line as let!
    function(pos, reltime=0.0; kwargs...)
        lines, sc, txt = plot2d_(pos, reltime; lines, sc, txt, kwargs...)
    end
end

```

and I call it with:

```julia
    if mod(i, 5) == 0
        plot2d(kps3.pos, reltime; zoom=ZOOM, front=FRONT_VIEW, 
                       segments=set.segments, fig="side_view")             
    end

```

This is nice, because now I can move this code into a package, and if I should need more variables for defining the state I do not have to change the code that is using this package…

Thanks a lot!

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 5, 2024, 5:14pm UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/4 "2024-05-05T17:14:57Z")

</div>

> [@bertschi](#):
>
> “let-over-lambda”

What does lambda mean in this context?

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [May 5, 2024, 6:13pm UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/5 "2024-05-05T18:13:11Z")

</div>

Anonymous functions are called/created with `lambda` in many functional languages (including Common Lisp where I had first encountered this idiom):

```julia
let cnt = 0
     x -> cnt += x
end

```

would be

```lisp
(let ((cnt 0))
   (lambda (x) (incf cnt x)))

```

in Common Lisp

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [May 5, 2024, 6:15pm UTC](https://discourse.julialang.org/t/can-i-use-a-closure-and-if-yes-how/113857/6 "2024-05-05T18:15:05Z")

</div>

More generally it’s a reference to “lambda calculus”.

> **[Lambda calculus](https://en.wikipedia.org/wiki/Lambda_calculus)**
>
> Lambda calculus (also written as λ-calculus) is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It is a universal model of computation that can be used to simulate any Turing machine. It was introduced by the mathematician Alonzo Church in the 1930s as part of his research into the foundations of mathematics.
> Lambda calculus consists of constructing lambda terms and performing reduction operat...
