# Capturing functions defined in global scope

**URL:** <https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400>\
**Category:** General Usage\
**Tags:** performance\
**Created:** [May 3, 2022, 4:33am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400 "2022-05-03T04:33:37Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jbu](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@jbu](https://discourse.julialang.org/u/jbu)\
**Post date:** [May 3, 2022, 4:33am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/1 "2022-05-03T04:33:37Z")

</div>

The [Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-global-variables) discuss the drawbacks of capturing global variables inside of functions. Are there any performance penalties for capturing _functions_ inside of other functions? For example,

```julia
function predict(x)
    # Returns some value
end

function loss(x, label)
    return sum(abs2, predict(x) .- label)
end

```

Will capturing `predict()` in `loss()` result in any performance penalties?

(I’m aware that functions are [`const` by default](https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Constants), but wanted to see if there were other considerations to be aware of.)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 3, 2022, 4:43am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/2 "2022-05-03T04:43:48Z")

</div>

No, there isn’t. If there were, then the functions `sum` and `abs2` and `-` would have the same problem, as would every other function in Base, and all other libraries too.

---

<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:** [May 3, 2022, 6:44am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/3 "2022-05-03T06:44:08Z")

</div>

> [@jbu](#):
>
> (I’m aware that functions are [`const` by default](https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Constants), but wanted to see if there were other considerations to be aware of.)

The only other thing is that if you use a closure then there is indeed a performance penalty.

For example, this is bad:

```julia
predict = x -> x^2

function loss(x, label)
    return sum(abs2, predict(x) .- label)
end

```

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [May 3, 2022, 10:07am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/4 "2022-05-03T10:07:59Z")

</div>

That is a bit unfortunate. I can appreciate why closures lead to boxing and hinder proper type inference. While it makes sense to me that `predict = x -> x^2` formally creates a closure, the return type is perfectly inferrable from `x` alone, isn’t it? Then why does inference on `loss` struggle here?

The manual mentions closures in the [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1.9-dev/manual/performance-tips/#man-performance-captured).  
I just wouldn’t think to apply the given example to the case at hand.

---

<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:** [May 3, 2022, 10:23am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/5 "2022-05-03T10:23:18Z")

</div>

> [@skleinbo](#):
>
> the return type is perfectly inferrable from `x` alone, isn’t i

Well, yes but what `predict` means is not predictable since anyone can just go and do `global predict = x -> string(x)` and now all of a sudden the return type is different.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 3, 2022, 10:32am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/6 "2022-05-03T10:32:07Z")

</div>

> [@kristoffer.carlsson](#):
>
> predict = x → string(x)

Isn’t this because `predict = x -> x^2` isn’t `const`. If you do

```julia
const predict = x -> x^2

```

or define `predict` inside a function, you are ok.

---

<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:** [May 3, 2022, 10:50am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/7 "2022-05-03T10:50:30Z")

</div>

Yes

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [May 3, 2022, 12:20pm UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/8 "2022-05-03T12:20:56Z")

</div>

Yes of course, silly me 😅

---

<div class="post-metadata">

**Author:** ![jbu](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@jbu](https://discourse.julialang.org/u/jbu)\
**Post date:** [May 5, 2022, 4:33am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/9 "2022-05-05T04:33:21Z")

</div>

Thanks, these are helpful clarifications!

> [@kristoffer.carlsson](#):
>
> The only other thing is that if you use a closure then there is indeed a performance penalty.

> [@DNF](#):
>
> Isn’t this because `predict = x -> x^2` isn’t `const` .

So it seems like the main issue is that the _variable_ holding the function needs to be `const`, correct? The documentation mentions that `function` and `struct` declarations automatically make the assignments `const`, but when doing `predict = x -> x^2` the variable `predict` is dynamic.

> [@DNF](#):
>
> …or define `predict` inside a function, you are ok.

Correct me if I’m wrong, but I think `const` is still needed even when `predict` is defined inside a function? For example,

```julia
function makepredict()
    predict = x -> x^2
    return predict
end

function g1(x)
    return x^2
end

g2 = makepredict()

const g3 = makepredict()

@btime for i=1:1000 g1(10) end # 0.877 ns (0 allocations: 0 bytes)
@btime for i=1:1000 g2(10) end # 6.766 μs (0 allocations: 0 bytes)
@btime for i=1:1000 g3(10) end # 0.877 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 5, 2022, 9:24am UTC](https://discourse.julialang.org/t/capturing-functions-defined-in-global-scope/80400/10 "2022-05-05T09:24:17Z")

</div>

> [@jbu](#):
>
> So it seems like the main issue is that the _variable_ holding the function needs to be `const` , correct?

Yeah, I think you would say that the _binding_ of the variable is const.

> [@jbu](#):
>
> but I think `const` is still needed even when `predict` is defined inside a function?  
> […]
> 
> ```julia
> g2 = makepredict()
> 
> ```

In this case, it is again the binding of the variable `g2` which is non-const. What I meant was that _inside_ a function you don’t need to do

```julia
function makepredict(x)
    const predict = x -> x^2 # don't need const here
    return predict(x)
end

```

If you bind the output of `makepredict()` to a variable in global scope, then `const` makes a difference again. So in global scope these are different:

```julia
g2 = makepredict()
const g3 = makepredict()

```

But if `g2 = makepredict()` happens inside a function, you don’t need `const`.
