# Allocations with anonymous functions

**URL:** <https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564>\
**Category:** Performance\
**Created:** [December 21, 2019, 10:02pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564 "2019-12-21T22:02:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [December 21, 2019, 10:02pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564/1 "2019-12-21T22:02:56Z")

</div>

I was experimenting with `StaticArrays.jl`, and noticed the following issue with memory allocations. Consider the following example code:

```julia
using Random
using StaticArrays

function f1(X, h, D)
    Y = D.*X- h;
    return Y
end

function f2(X)
    D = @SVector [0.1,1,1]; 
    h = @SVector [0.1,0,0]; 
    Y = D.*X- h;
    return Y
end

function apply_n_times(X, f_func, n)
    Y = copy(X)
    for j = 1:n
        Y = f_func(Y);
    end
    return Y
end

Random.seed!(100);
X = @SVector randn(3);

D = @SVector [0.1,1,1]; 
h = @SVector [0.1,0,0]; 

n = 10^4;
@time Y = apply_n_times(X, X->f1(X,h,D), n);
println(Y)
@time Y = apply_n_times(X, f2, n);
println(Y)

```

If I then run this a second time (after things get precompiled), I see the following results:

```julia
julia> @time Y = apply_n_times(X, X->f1(X,h,D), n);
  0.017026 seconds (37.15 k allocations: 1.533 MiB)

julia> @time Y = apply_n_times(X, f2, n);
  0.000051 seconds (5 allocations: 192 bytes)

```

Showing a substantial improvement in performance when I do not use the anonymous function. This leads to the following questions:

1. Is this an inherent issue when using anonymous functions, or is it some combination of using them with `StaticArrays.jl`?
2. Is there a way to avoid this performance hit with anonymous functions?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 21, 2019, 10:15pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564/2 "2019-12-21T22:15:30Z")

</div>

> [@gideonsimpson](#):
>
> Is there a way to avoid this performance hit

if there is a performance hit, think of the fact that it is the first time compiler sees the function – since it’s a anonymous function just got defined in the same line.

---

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [December 21, 2019, 10:17pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564/3 "2019-12-21T22:17:20Z")

</div>

Nope, if I do:

```julia
g = X->f1(X,h,D)
@time Y = apply_n_times(X, g, n);

```

it’s just as bad

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 21, 2019, 10:33pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564/4 "2019-12-21T22:33:32Z")

</div>

You are measuring compilation time. Use the `@btime` macro from BenchmarkTools.jl.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [December 21, 2019, 10:56pm UTC](https://discourse.julialang.org/t/allocations-with-anonymous-functions/32564/5 "2019-12-21T22:56:02Z")

</div>

> [@kristoffer.carlsson](#):
>
> You are measuring compilation time.

Partially, but that’s not the main problem. The real issue is this:

```julia
X = @SVector randn(3)

D = @SVector [0.1,1,1]
h = @SVector [0.1,0,0]

g = X->f1(X,h,D)

```

which the OP appears to be running in the global scope, so `g` is holding references to global variables.

@gideonsimpson Here’s a self contained example showing that correctly used anonymous functions carry no runtime burden:

```julia
using Random
using StaticArrays

function f1(X, h, D)
    Y = D.*X - h; 
    return Y
end

function f2(X)
    D = @SVector [0.1,1,1]; 
    h = @SVector [0.1,0,0]; 
    Y = D.*X - h;
    return Y
end

function apply_n_times(X, f_func, n)
    Y = copy(X)
    for j = 1:n
        Y = f_func(Y);
    end
    return Y
end

Random.seed!(100);
let
    X = @SVector randn(3);

    D = @SVector [0.1,1,1]; 
    h = @SVector [0.1,0,0]; 

    n = 10^4;

    g = X -> f1(X, h, D)
    
    @btime apply_n_times($X, $g, $n); # 22.285 μs (0 allocations: 0 bytes)
    @btime apply_n_times($X, $f2, $n); # 22.287 μs (0 allocations: 0 bytes)
end

```

Here I used a `let` block to introduce a local scope so that the compiler was able to be guaranteed that the values of `X`, `D` and `h` wouldn’t change during the evaluation which enabled many optimizations. There are other ways of doing this, such as declaring `X`, `D` and `h` to be `const` or by using a closure to produce `g` (though that can be impacted by the closure performance bug if not done carefully).
