# Function inside struct allocates when referenced

**URL:** <https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785>\
**Category:** New to Julia\
**Tags:** function\
**Created:** [November 4, 2023, 4:55am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785 "2023-11-04T04:55:37Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![izod2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/izod2/32/202945_2.png) [@izod2](https://discourse.julialang.org/u/izod2)\
**Post date:** [November 4, 2023, 4:55am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/1 "2023-11-04T04:55:37Z")

</div>

In the example below, if `box1` is passed as an argument to `calcA`, then calling its function `box1.func` leads to allocation.

However, if `box1.func` is passed as a direct argument to `calcB`, then there is no allocation.

Can you help me understand this behavior?

```julia
struct Box
    func :: Function
    func_array :: Array{Function, 1}
end 

function f1(x)
    return 1
end

box1 = Box(
    func = f1,
    func_array = [f1,f1,f1,f1]
)
 
function calcA(box)
    for i=1:Int(1e6)
        y = box.func(i)
    end
end
@time calcA(box1) 
@time calcA(box1) 

function calcB(box, f)
    for i=1:Int(1e6)
        y = f(i)
    end
end
@time calcB(box1, box1.func) 
@time calcB(box1, box1.func) 

```

Output

```julia
 0.027969 seconds (1.00 M allocations: 15.416 MiB, 9.45% gc time, 21.37% compilation time)
 0.019493 seconds (999.49 k allocations: 15.251 MiB)
 0.000387 seconds (1.63 k allocations: 107.531 KiB, 94.27% compilation time)
 0.000008 seconds

```

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [November 4, 2023, 5:10am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/2 "2023-11-04T05:10:49Z")

</div>

`Function` is an abstract type, and you may need to parameterize your struct to avoid allocations

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 4, 2023, 5:51am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/3 "2023-11-04T05:51:10Z")

</div>

See the Performance tips in the manual:

[https://docs.julialang.org/en/v1/manual/performance-tips/](https://docs.julialang.org/en/v1/manual/performance-tips/)

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [November 4, 2023, 11:17am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/4 "2023-11-04T11:17:36Z")

</div>

So in concrete terms, this is what a more efficient `Box` would look like:

```julia
struct Box{F}
    func::F
end

```

No need to specify `F <: Function`, since there are objects that are not functions but still callable.

However, this trick will not work well for `func_array`. Indeed, each function `f` in Julia has its own type `typeof(f)`, and so you cannot specify a concrete type for the array elements unless all of its elements have the same type, i.e. they are the same function. Which would make said array useless.  
Why do you need an array of functions in your use case?

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [November 4, 2023, 12:26pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/5 "2023-11-04T12:26:05Z")

</div>

Minor addition to @gdall’s comment: Instead of an array of function, a tuple of function should work just fine (well as long as it doesn’t get too long, but I have no good idea what “too long” is in this context).

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 4, 2023, 1:13pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/6 "2023-11-04T13:13:09Z")

</div>

> [@gdalle](#):
>
> each function `f` in Julia has its own type

Does not hold for closures, they don’t have to be singleton types:

```julia
julia> f(n) = let n = n
         x -> x + n
       end
f (generic function with 1 method)

julia> typeof(f(1)) == typeof(f(2)) <: Function
true

```

---

<div class="post-metadata">

**Author:** ![izod2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/izod2/32/202945_2.png) [@izod2](https://discourse.julialang.org/u/izod2)\
**Post date:** [November 6, 2023, 5:02am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/7 "2023-11-06T05:02:56Z")

</div>

Thanks for the concrete example!

> Why do you need an array of functions in your use case?

The `Box` struct is meant to represent a network/array of elements, where each element has an associated “behavior” function. There can be many elements (dozens/hundreds), but there are only a handful of behavior functions - hence the function array. (the actual meaning of the “behavior” function is not relevant for the MWE).

Instead of an array of functions, would it be better to have an array of strings holding function names and then add a “function lookup” function based on that string, e.g.?

```julia
struct Box
    fname_array :: Array{String, 1}
end 

function lookup(x, name)
    if name == "f1"
        return f1(x)
    elseif ...
end

# example: call the i-th element function on variable x
lookup(x, box1.fname_array[i])

```

or maybe there’s a better way altogether.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [November 6, 2023, 6:10am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/8 "2023-11-06T06:10:05Z")

</div>

I don’t think it really matters in your case how you store the information of which function to call. There will always be a dynamic dispatch since the compiler can never known which functions there will be. Making things more stable in the struct only shifts this to a different place.

What you can try to improve things (assuming all behavior function have the same signature): use [`FunctionWrappers.jl`](https://github.com/yuyichao/FunctionWrappers.jl). I have never used it so I don’t know how well it will work.  
In principle it allows you to put a concrete type on the vector like so

```julia
struct Box
    fname_array :: Array{FunctionWrapper{Outputtype,(Input1, input2,...}, 1}
end 

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 6, 2023, 7:08am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/9 "2023-11-06T07:08:57Z")

</div>

> [@izod2](#):
>
> The `Box` struct is meant to represent a network/array of elements, where each element has an associated “behavior” function. There can be many elements (dozens/hundreds), but there are only a handful of behavior functions - hence the function array.

What are the behavior functions like? Giving them all the same type would be a solution.

Or you could do something like this to prevent run time dispatch:

```julia
struct Box
  behavior_function_code::UInt8
end

execute_behavior(code::UInt8, args...) =
  if code == 0
    bf0(args...)
  if code == 1
    bf1(args...)
  elseif
    bf2(args...)
  end

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 6, 2023, 2:43pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/10 "2023-11-06T14:43:48Z")

</div>

> [@nsajko](#):
>
> ```julia-auto
> execute_behavior(code::UInt8, args...) =
> if code == 0
> bf0(args...)
> if code == 1
> bf1(args...)
> elseif
> bf2(args...)
> end
> 
> ```

Nice dispatch. Have you considered using multiple disparch?

```julia-auto
execute_behavior(code::UInt8, args...) = bf(Val(code), args...)
bf(::Val{0x0}, args...) = 0
bf(::Val{0x1}, args...) = 1
bf(::Val{0x2}, args...) = 2

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 6, 2023, 2:47pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/11 "2023-11-06T14:47:16Z")

</div>

I specifically said right there that the goal is to prevent run time dispatch. Is that not the goal here?

---

<div class="post-metadata">

**Author:** ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)\
**Post date:** [November 6, 2023, 2:55pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/12 "2023-11-06T14:55:48Z")

</div>

@mkitti 's solution doesn’t use runtime dispatch because `Val` tells the compiler to consider the parameter value during compilation. See [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 6, 2023, 3:08pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/13 "2023-11-06T15:08:25Z")

</div>

You can see below that Julia is able to constant propagate through the multiple dispatch.

```julia
julia> f() = execute_behavior(0x1)
f (generic function with 1 method)

julia> f()
1

julia> @code_typed f()
CodeInfo(
1 ─ return 1
) => Int64

julia> @code_warntype f()
MethodInstance for f()
  from f() @ Main REPL[12]:1
Arguments
  #self#::Core.Const(f)
Body::Int64
1 ─ %1 = Main.execute_behavior(0x01)::Core.Const(1)
└── return %1

```

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [November 6, 2023, 3:10pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/14 "2023-11-06T15:10:22Z")

</div>

It would probably help to know a bit more about what you precisely want to achieve.  
Most likely, Functionwrappers will do the job.  
Personally, when I needed a collection of functions in the past, the correct solution turned out to be a vector of functors (callable structs).  
This is imo the best way to approach this when your functions are all similar in some sense but depend on additional data which is different for. For example

```julia
F1(x) = 2sin(3x)
F2(x) = 3cos(1x)
[...]

```

Can be represented by callable structs which save the amplitude and phase of the sine function.

Of course it might also be that your functions are user defined, in which case functionwrappers are probably the only way to go.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 6, 2023, 3:50pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/15 "2023-11-06T15:50:48Z")

</div>

> [@mkitti](#):
>
> You can see below that Julia is able to constant propagate through the multiple dispatch.

What is this meant to prove? It doesn’t seem like `0x1` would be a constant in the real code.

> [@filchristou](#):
>
> doesn’t use runtime dispatch because `Val` tells the compiler to consider the parameter value during compilation.

Moving a value into the type domain involves multiple dispatch, that’s exactly what I was referring to.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [November 6, 2023, 3:59pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/16 "2023-11-06T15:59:04Z")

</div>

> [@nsajko](#):
>
> What is this meant to prove? It doesn’t seem like `0x1` would be a constant in the real code.

There is no runtime dispatch involved in my use of multiple dispatch. Your `if` statement and my use of multiple dispatch can be compiled down to the same machine code.

In fact, due to simplicity Julia inlined the entire thing even before using LLVM’s JIT.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 6, 2023, 4:20pm UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/17 "2023-11-06T16:20:16Z")

</div>

> [@mkitti](#):
>
> There is no runtime dispatch involved

Yeah, but this is specifically because in your example the run time dispatch gets constant folded away.

> [@mkitti](#):
>
> Your `if` statement and my use of multiple dispatch can be compiled down to the same machine code.

Only when the argument is a compile-time constant. Which would be pointless.

---

<div class="post-metadata">

**Author:** ![izod2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/izod2/32/202945_2.png) [@izod2](https://discourse.julialang.org/u/izod2)\
**Post date:** [November 7, 2023, 12:24am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/18 "2023-11-07T00:24:02Z")

</div>

Thanks for helping me wrap my mind around this. A couple of questions:

Can you comment on what “giving them all the same type” means?  
In my case, all `bf`’s functions take the same Float input (coordinate x) and return a Float output.

In your example, can `code` be a string and `behavior_function_code` a string array?

Finally, it was noted in the comment above:

> I don’t think it really matters in your case how you store the information of which function to call. There will always be a dynamic dispatch since the compiler can never known which functions there will be.

but it seems your approach avoids dynamic dispatch?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 7, 2023, 1:58am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/19 "2023-11-07T01:58:54Z")

</div>

> [@izod2](#):
>
> Can you comment on what “giving them all the same type” means?

> [@nsajko](#):
>
> Does not hold for closures, they don’t have to be singleton types:

By default, a function is an instance of a singleton type, meaning that type only has 1 instance, the function itself. However, that is not necessarily the case; if a function were to contain data from a local scope, then it would not have a singleton type. The non-singleton function factory example nsajko provided is a bit indirect, it’d be clearer to write out the underlying [functors](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects) with a type that subtypes `Function`, making them functions. There would still only be 1 method table associated with the functors’ type, but the functors would act differently because of the data they contain. Of course, this still restricts the functors to do almost the same thing, so it might not be applicable to your use case. FunctionWrappers.jl lets the multiple input functions have different method tables and types as a tradeoff for attaching a call signature restriction. (Normally, a function has multiple methods, and each method can be compiled for multiple call signatures; a call is dispatched to a method based on the function’s type as well as the arguments’ types).

To expand on the explicitness, unlike writing out a functor type to contain data in manually annotated fields, closures handle it implicitly so it’s not visible in one place:

```julia-auto
julia> f(n, m) = let n = n, m = m
         foo(x) = x+n # 1st method captures n
         # maybe a lot of other code
         foo() = m # 2nd method captures m
       end
f (generic function with 1 method)

julia> f(1, 1.0) # type parameters means function contains both n and m
(::var"#foo#1"{Int64, Float64}) (generic function with 2 methods)

```

Instantiating functors also don’t have to deal with variable scoping rules; closures are local scopes that technically capture _variables_, not data at instantiation, and any reassignment prevents the compiler from [inferring the variable’s type well](https://discourse.julialang.org/t/can-someone-explain-closures-to-me/105605/2), even if [unnecessary and accidental](https://discourse.julialang.org/t/pinv-not-type-stable/103885/10).

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 7, 2023, 10:36am UTC](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785/20 "2023-11-07T10:36:03Z")

</div>

> [@izod2](#):
>
> Can you comment on what “giving them all the same type” means?  
> In my case, all `bf`’s functions take the same Float input (coordinate x) and return a Float output.

In Julia there is no connection between the type of a function and possible type signatures. Type signatures belong to methods, not functions (while a function may have arbitrarily many methods attached to it). Benny already expanded on the meaning, however if you want us to help, you have to give us more information on your functions. Also it’s important if there’s just a fixed number of them, or will users of your package be able to add more, etc. Are the functions all defined directly in your source code? If possible just give your source code.

> [@izod2](#):
>
> In your example, can `code` be a string and `behavior_function_code` a string array?

Sure, but that wouldn’t be very efficient. I just used the `UInt8` as an example, in practice I’d probably use something enum-like, for clarity. There’s a few different user packages that have `Enum` as a prefix to their name, so you can pick and choose. There’s also some enum-like functionality built-into Julia, but I don’t like that.

> [@izod2](#):
>
> but it seems your approach avoids dynamic dispatch?

Yes.

[Next page](https://discourse.julialang.org/t/function-inside-struct-allocates-when-referenced/105785.md?page=2)
