# Function definition inside let-block impacting performance?

**URL:** <https://discourse.julialang.org/t/function-definition-inside-let-block-impacting-performance/110007>\
**Category:** Performance\
**Tags:** question\
**Created:** [February 9, 2024, 8:06pm UTC](https://discourse.julialang.org/t/function-definition-inside-let-block-impacting-performance/110007 "2024-02-09T20:06:28Z")\
**Posts on this page:** 1\
**Showing post:** 26

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 12, 2024, 4:48pm UTC](https://discourse.julialang.org/t/function-definition-inside-let-block-impacting-performance/110007/26 "2024-02-12T16:48:22Z")

</div>

> [@Benny](#):
>
> IMO it would be more confusing to make 2 different functions with different types share a name, which isn’t possible in the global scope

This already happens whenever you conditionally assign an anonymous function to a single identifier:

```julia
if cond; f=x->x else f=x->x^2 end  

```

the idea here is just to extend this to local named functions, and to use similar semantics that we use for local constants, if we can find agreeable rules for that.

The difference when you conditionally define a named function at global scope to be one thing or another is that there aren’t two types under the hood; only one version is compiled. But this is under the hood anyway; most users don’t notice.

> [@](#):
>
> Local `const` wouldn’t help because adding methods is not a reassignment.

The idea here is to treat local named functions as local `const`s with regard to how their initial declarations should interact with conditionals, and add some minor additional rules to handle how methods can be added (i.e. only allow methods to be added within the same branch where the function is declared).

> [@](#):
>
> In general, that is impossible, or rather `a` must have `Any` type.

For the general case, I agree. For example, `a` must certainly be in a `Box{Any}` here:

```julia
f, g = let a = 0.5
    _f(x) = (a = a * x; a)
    _g(x) = (a = a / x; a)
    _f, _g
end

```

This is discussed in the first “difficulty” of idea 3 [here](https://discourse.julialang.org/t/rfc-some-ideas-to-tackle-15276-performance-of-captured-variables-in-closures/95260). We can annotate the types of either `x` or `a` to fix this, which of course limits the usefulness of lowering to use type inference here.

However, there are many “special cases” where closures either mutate a capture independent of their arguments, or capture something which is mutated in their parent scope—if lowering had access to return types it could correctly parameterize the box. [Here’s a tricky example](https://discourse.julialang.org/t/spawn-large-memory-allocation-reduced-when-some-code-abstracted-out-in-a-function/88691) of this.

> [@](#):
>
> the closures’ instances are containing redundant information

Ah, good point. Even if `Iseven` and `Isodd` access a shared storage element, if I construct an array of `Iseven`s and an array of `Isodd`s this information will be copied twice.

> [@](#):
>
> editing my earlier example:

If I’m not mistaken, this suffers from the same issue.

---

_[View the full topic](https://discourse.julialang.org/t/function-definition-inside-let-block-impacting-performance/110007)._
