# Efficient closures

**URL:** https://discourse.julialang.org/t/efficient-closures/41262
**Category:** Performance
**Tags:** question, closure
**Created:** [June 12, 2020, 12:01pm UTC](https://discourse.julialang.org/t/efficient-closures/41262 "2020-06-12T12:01:15Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![tfr](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@tfr](https://discourse.julialang.org/u/tfr)
#### Post date: [June 12, 2020, 12:01pm UTC](https://discourse.julialang.org/t/efficient-closures/41262/1 "2020-06-12T12:01:15Z")

</div>

Hello.  
I have a function of many variables, `hermite_interpolation(t, t_array, f_array, df_array)`, and I want to use this function as the argument of another function, that I shall call `do_something(pulse)`. However, the argument `pulse` of the function `do_something` must be a function of the time `t` only. At first I was simply defining the function

```julia
pulse = t-> hermite_interpolation(t, t_array, filtered_f, filtered_df)

```

and feeding it to `do_something`. Afterwards I learned that it was actually better to define

```julia
pulse2 = let t_array = t_array,
             f_array = filtered_f,
             df_array = filtered_df
             t-> hermite_interpolation(t, t_array, f_array, df_array)
	     end

```

I benchmarked both functions, and I obtained

```julia
julia> @benchmark pulse($tf)
BenchmarkTools.Trial:
  memory estimate: 48 bytes
  allocs estimate: 3
  --------------
  minimum time: 80.339 ns (0.00% GC)
  median time: 88.953 ns (0.00% GC)
  mean time: 101.802 ns (6.52% GC)
  maximum time: 17.307 μs (99.37% GC)
  --------------
  samples: 10000
  evals/sample: 949

```

```julia
julia> @benchmark pulse2($tf)
BenchmarkTools.Trial:
  memory estimate: 32 bytes
  allocs estimate: 2
  --------------
  minimum time: 57.724 ns (0.00% GC)
  median time: 64.536 ns (0.00% GC)
  mean time: 73.016 ns (5.11% GC)
  maximum time: 14.597 μs (99.49% GC)
  --------------
  samples: 10000
  evals/sample: 973

```

I also benchmarked `hermite_interpolation(t, t_array, f_array, df_array)` and I got

```julia
julia> @benchmark hermite_interpolation($tf, $t_array, $filtered_f, $filtered_df)
BenchmarkTools.Trial:
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 29.318 ns (0.00% GC)
  median time: 31.083 ns (0.00% GC)
  mean time: 34.351 ns (0.00% GC)
  maximum time: 666.528 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 995

```

Here we se that the original function `hermite_interpolation(tf, t_array, filtered_f, filtered_df)` is still much faster than the closures `pulse` and `pulse2`.

My question is, is there a way to define faster closures? I would appreciate any help.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [June 12, 2020, 1:39pm UTC](https://discourse.julialang.org/t/efficient-closures/41262/2 "2020-06-12T13:39:26Z")

</div>

It will be easier to help if you can provide a working self-contained example, otherwise we’re kind of just guessing.

However, the first thing I notice in your case is that `pulse` and `pulse2` are themselves non-constant global variables. That means you need to interpolate them into the benchmark as well, e.g.:

```julia
@benchmark ($pulse)($tf)
@benchmark ($pulse2)($tf)

```

---

<div class="post-metadata">

### Author: ![tfr](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@tfr](https://discourse.julialang.org/u/tfr)
#### Post date: [June 12, 2020, 6:25pm UTC](https://discourse.julialang.org/t/efficient-closures/41262/3 "2020-06-12T18:25:45Z")

</div>

I guess you solved the problem. I was not benchmarking the functions correctly. So let us suppose that I define the functions

```julia
f1(x) = x + 1
f2 = x-> x+ 1

```

I thought that both definitions where equivalent, but apparently this is not the case. Could someone elaborate a bit about that?

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [June 12, 2020, 7:01pm UTC](https://discourse.julialang.org/t/efficient-closures/41262/4 "2020-06-12T19:01:56Z")

</div>

The syntax

```julia
f1(x) = x + 1

```

implicitly makes `f1` const. Try doing:

```julia
julia> f1(x) = x + 1
f1 (generic function with 1 method)

julia> f1 = "hello"
ERROR: invalid redefinition of constant f1

```

You can do `const f2 = x -> x + 1` to get the same performance at global scope.

Note that this is only relevant for global variables: the slowness comes when you have a variable which is non-const _and_ global. In a local scope you don’t need to worry about marking `const` (in fact, you can’t).

---

<div class="post-metadata">

### Author: ![tfr](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@tfr](https://discourse.julialang.org/u/tfr)
#### Post date: [June 13, 2020, 6:18am UTC](https://discourse.julialang.org/t/efficient-closures/41262/5 "2020-06-13T06:18:23Z")

</div>

Great. Thank you for the detailed explanation!
