# Structures containing a function field

**URL:** <https://discourse.julialang.org/t/structures-containing-a-function-field/65696>\
**Category:** Performance\
**Created:** [August 2, 2021, 6:48pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696 "2021-08-02T18:48:02Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 2, 2021, 6:48pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/1 "2021-08-02T18:48:02Z")

</div>

I would like to include a function as part of a Julia object (`struct`). However, when I, for example, execute

```julia
using BenchmarkTools

func(x) = 2*x^2

struct Test
    k :: Float64
    V :: Array{Float64, 1}
    fn :: Function
end

T = Test(0.5, collect(1.0:10.0), func)
@btime @. $T.V = $T.k*$T.fn($T.V)
T = Test(0.5, collect(1.0:10.0), func)
@btime @. $T.V = $T.k*$func($T.V)

```

I get quite a lot of allocated memory when the function from the object’s field is used in the calculations (1st calculation):

```julia
  181.873 ns (5 allocations: 112 bytes)
  9.416 ns (0 allocations: 0 bytes)

```

Is there any way to solve this problem? (I am using `v1.7.0-beta3` because of the new Mac M1, but I It shouldn’t make any difference, I guess.)

---

<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:** [August 2, 2021, 6:50pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/2 "2021-08-02T18:50:19Z")

</div>

> [@aaraujo71](#):
>
> ```julia
> struct Test
> k :: Float64
> V :: Array{Float64, 1}
> fn :: Function
> end
> 
> ```

```julia
struct Test{T}
    k :: Float64
    V :: Array{Float64, 1}
    fn :: T
end

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 2, 2021, 6:50pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/3 "2021-08-02T18:50:56Z")

</div>

> [@aaraujo71](#):
>
> Is there any way to solve this problem?

Parameterize the function in the type:

```julia
julia> using BenchmarkTools

julia> func(x) = 2*x^2
func (generic function with 1 method)

julia> struct Test{F}
           k :: Float64
           V :: Array{Float64, 1}
           fn :: F
       end

julia> T = Test(0.5, collect(1.0:10.0), func)
Test{typeof(func)}(0.5, [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0], func)

julia> @btime @. $T.V = $T.k*$T.fn($T.V)
  12.173 ns (0 allocations: 0 bytes)

```

(@jling beat me)

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 2, 2021, 6:54pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/4 "2021-08-02T18:54:33Z")

</div>

just that? Wow. Thank you very much. I still have problems understanding why parameterization is so important.

---

<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:** [August 2, 2021, 6:56pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/5 "2021-08-02T18:56:58Z")

</div>

because `Function` is an abstract type. If you need speed, you need to tell compiler to specialize according to “what function does this struct contain”.

`func` has type `typeof(func)`, if your struct is parametrized by this, then `T.fn` is type stable (constant propagated?)

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 2, 2021, 7:03pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/6 "2021-08-02T19:03:30Z")

</div>

Is it because I have to tell exactly what type of function the field is (size, number of arguments, etc.)?

---

<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:** [August 2, 2021, 7:06pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/7 "2021-08-02T19:06:12Z")

</div>

not really, Julia doesn’t have typed function. each function just has its own type that’s all.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [August 2, 2021, 7:21pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/8 "2021-08-02T19:21:06Z")

</div>

Just so you know, this is a bit of an anti-pattern in Julia. Julia is not object-oriented to the extent python is, and you shouldn’t store methods inside objects like this, partly due to the problems you are seeing here.

Instead of `obj.fun()`, define `fun(obj::Object) = ...`

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 3, 2021, 10:19am UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/9 "2021-08-03T10:19:32Z")

</div>

The reason I want to store functions inside an object is that I am trying to program a new NN type, and I want the user to define activation functions and their derivatives when the object is created, the same way that coefficient arrays and other parameters are stored when the NN object is created. Functions that later act on the NN object are executed as `function(nn :: NNObject)`.

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 3, 2021, 10:28am UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/10 "2021-08-03T10:28:19Z")

</div>

And if I want to define a second object containing a function to be used in the first object, using an inner constructor, such as the following example?

```julia
using BenchmarkTools

f(x) = 2*x^2

struct Fn{F}
    fn :: F
end

struct Test
    k :: Float64
    V :: Array{Float64, 1}
    fn :: Fn
    function Test(n, k, fn)
        V = rand(n)
        fn = Fn(fn)
        return new(k, V, fn)
    end
end

T = Test(10, 0.5, f)
@btime @. $T.V = $T.k*$T.fn.fn($T.V)

```

I get

```julia
  460.868 ns (6 allocations: 128 bytes)
10-element Vector{Float64}:

```

I can see that I have to pass the function parameter in the first object, but I just don’t see how.

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [August 3, 2021, 3:16pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/11 "2021-08-03T15:16:00Z")

</div>

```julia
struct Test{F}
    k :: Float64
    V :: Array{Float64, 1}
    fn :: Fn{F}
    function Test(n, k, fn)
        V = rand(n)
        return new{typeof(fn)}(k, V, Fn(fn))
    end
end
 
  7.000 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 3, 2021, 4:09pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/12 "2021-08-03T16:09:50Z")

</div>

You can either do what Jeff suggested above, or parameterize the complete type of the `fn` variable:

```julia
julia> struct Test{FnType}
           k :: Float64
           V :: Array{Float64, 1}
           fn :: FnType
       end
       Test(n::Int,k,fn::Function) = Test(k,rand(n),Fn(fn))
Test

julia> f(x) = 2*x^2
f (generic function with 1 method)

julia> struct Fn{F}
           fn :: F
       end

julia> Test(10,0.5,f)
Test{Fn{typeof(f)}}(0.5, [0.373040251764891, 0.3254890833516999, 0.9292136075453126, 0.15979121840237576, 0.7250485410648198, 0.6981743589031963, 0.12171709120019081, 0.5225742664754627, 0.6993845264127123, 0.5729168135399181], Fn{typeof(f)}(f))

julia> @btime @. $T.V = $T.k*$T.fn.fn($T.V)
  8.032 ns (0 allocations: 0 bytes)

```

The point is that a function is an abstract type, thus a struct that contains a function must be parameterized such that it is concrete for a specific type of function. In the same way, your `struct Fn{F}` is also an abstract type, which assumes a concrete type if `F` is defined. Then, for instance,

```julia
julia> Fn(sin)
Fn{typeof(sin)}(sin)

```

this is a concrete instance of `Fn`, specific for the `sin` function. The ` Test` has to be instantiated to a concrete type, by informing that the function is `sin`, or that the complete `fn` is of type `Fn{typeof(sin)}` .

What to use depends on what is clearer for the code, and which option is more convenient for the dispatch rules that these types can participate in your code.

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [August 3, 2021, 5:50pm UTC](https://discourse.julialang.org/t/structures-containing-a-function-field/65696/13 "2021-08-03T17:50:46Z")

</div>

Thank you very much.
