# How to avoid boxed function names in closures?

**URL:** <https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579>\
**Category:** Performance\
**Tags:** closure\
**Created:** [April 4, 2021, 10:35pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579 "2021-04-04T22:35:24Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [April 4, 2021, 10:35pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/1 "2021-04-04T22:35:24Z")

</div>

Hello! In order to avoid performance problems, I would like to know whether boxes can be avoided in two kinds of closures. Without closures, all problems mentioned below disappear. I’m using Julia 1.6.0.

### Keyword argument in the presence of other methods

Consider the following example:

```julia-auto
function h1()
    f(x, y) = x+y
    f(x; p = 0) = x+p
    return f
end
f = h1()

```

Then `@code_warntype f(1)` contains the lines

```julia-auto
Body::Any
1 ─ %1 = Core.getfield(#self#, Symbol("#f#1"))::Core.Box

```

You also see a box in `@code_warntype f(1; p = 1)`, but not in `@code_warntype f(1,1)`. The problem disappears if the keyword argument is removed from the second method, but also if instead the first method is removed, so that there is only the second method left (_with_ the keyword argument). Is there a way to have multiple methods and keyword arguments at the same time without creating boxes?  
The GitHub issue #19668 might be related, but it has been fixed already. (I tried to insert a link, but Discourse wouldn’t let me do it.)

### Function calling itself

In the example

```julia-auto
function h2()
    f(x, y) = x+y
    f(x) = f(x, x)
    return f
end
f = h2()

```

the output of `@code_warntype f(1)` contains

```julia-auto
Body::Any
1 ─ %1 = Core.getfield(#self#, :f)::Core.Box

```

In this specific example I can of course avoid that `f` calls itself by saying

```julia-auto
function h3()
    g(x, y) = x+y
    f(x, y) = g(x, y)
    f(x) = g(x, x)
    return f
end
f = h3()

```

and this fixes the problem. But what do I do for a truly recursive function, say

```julia-auto
function h4()
    f(n) = n == 0 ? 1 : n*f(n-1)
    return f
end
f = h4()

```

Is there a way to avoid the creation of boxes in this case?

Thanks a lot!

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [April 5, 2021, 12:51pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/2 "2021-04-05T12:51:28Z")

</div>

Callable structs seem to solve this particular issue:

```julia
struct H1<:Function end

(f::H1)(x, y) = x+y
(f::H1)(x; p = 0) = x+p

f = H1()

#etc...

```

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [April 5, 2021, 1:06pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/3 "2021-04-05T13:06:44Z")

</div>

I recognize that you’re providing a MWE here and that your real code is presumably much more complicated, but just forcing the compiler to specialize a bit more aggressively does the trick for me in `h1`:

```julia
function h1()
  f(x,y) = x+y
  f(x::T, p::T=zero(T)) where{T} = x+p # used , instead of ;, see edit.
  f
end

f=h1()
@code_warntype f(1) # Body::Int64, looks good.

```

EDIT: So, interestingly, I realize that I mistakenly just put a comma instead of a semicolon for the kwarg version. Changing that comma to the semicolon broke the type inference, so this actually seems like something to do with the keyword arg parsing.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [April 5, 2021, 1:25pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/4 "2021-04-05T13:25:11Z")

</div>

Thanks for this very nice workaround with constructors!  
The issue [#19668](https://github.com/JuliaLang/julia/issues/19668) was about performance problems related to constructors with keyword arguments, and it was fixed in 2018. Could this indicate that the problem I’m describing here can be fixed in a similar way?

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [April 5, 2021, 5:14pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/5 "2021-04-05T17:14:40Z")

</div>

Yes, I gave a MWE. My motivation is twofold:

1. Independently of the application I have in mind, I wonder whether this is a problem with Julia that one should report as an issue on GitHub. It’s unclear to me whether the boxes the compiler inserts in my examples are strictly necessary or could be omitted.
2. Originally, I was writing a function that extends the methods of a given function (with no restrictions on the return type). Expanding on my first example, I would have

```julia
function h1(g::Function)
    f(x...) = g(x...)
    f(x; p = 0) = g(x, p)
    return f
end
f = h1(+)

```

If I (naively) adapt the callable struct solution mentioned above,

```julia
struct H1 <: Function
    g::Function
end
(f::H1)(x...) = f.g(x...)
(f::H1)(x; p = 0) = f.g(x, p)
ff = H1(+)

```

then it seems I lose type stability completely. For example, I get

```julia
julia> @code_warntype ff(1, 2)
Variables
  f::H1
  x::Tuple{Int64, Int64}

Body::Any
1 ─ %1 = Base.getproperty(f, :g)::Function
│ %2 = Core._apply_iterate(Base.iterate, %1, x)::Any
└── return %2

```

The closure approach is type stable as long as I use the first method. For example, `@code_warntype f(1, 2)` reports `Body::Int64`. Is there a solution that is always type stable?

EDIT: If one uses a parametrized type,

```julia
struct H1{T} <: Function where T <: Function
    g::T
end

```

then one gets type stability.

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [April 5, 2021, 5:41pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/6 "2021-04-05T17:41:49Z")

</div>

This is all interesting. Even if you completely statically type the kwarg version you get type instability:

```julia
function h1()
  _f(x,y) = x+y
  _f(x::Float64; p::Float64=0.0) = x+p
  _f
end
const f = h1()
@code_warntype f(1.1) # bad

```

I think I’m really out of my depth here. But I’d definitely be interested to learn the answer about this behavior from somebody who understands it. I’m not even sure I see what’s going on here well enough to suggest if it should be an issue.

EDIT:

So, this code in a script file doesn’t even run with `include`, and the error message is probably helpful about what’s going on:

```julia
# an empty object that we'll add methods to, like the struct suggestion.
struct Example end

# Instantiate some unique one.
sample_fn = Example() 

# A function to add methods.
function addmethods!(fn::F) where{F}
  (f::F)(x, y) = x+y
  (f::F)(x; p=0) = x+p
  nothing
end

# when you try to include:
ERROR: LoadError: syntax: Global method definition around /home/cg/furthertest.jl:10 needs to be placed at the top level, or use "eval".

```

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 5, 2021, 8:29pm UTC](https://discourse.julialang.org/t/how-to-avoid-boxed-function-names-in-closures/58579/7 "2021-04-05T20:29:18Z")

</div>

If you use inner functions, you restrict the inner function to the scope of the outer function (in which it is defined in). With the syntax `(f::F)(x, y) = x+y` what you are trying to do is to define a _global scope_ function that is called every time an object of type `F` is treated as a function (in that scope, `fn(1, 2)` would return `3`). However, this should not be possible to do with an inner function, because it does change how objects of type `F` behave anywhere in the program, hence the error.
