# Passing a struct to a function allocates whereas passing an array does not

**URL:** https://discourse.julialang.org/t/passing-a-struct-to-a-function-allocates-whereas-passing-an-array-does-not/103303
**Category:** Performance
**Tags:** array, memory-allocation, struct
**Created:** [August 28, 2023, 5:29pm UTC](https://discourse.julialang.org/t/passing-a-struct-to-a-function-allocates-whereas-passing-an-array-does-not/103303 "2023-08-28T17:29:50Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![simon79](https://avatars.discourse-cdn.com/v4/letter/s/76d3ee/32.png) [@simon79](https://discourse.julialang.org/u/simon79)
#### Post date: [August 28, 2023, 5:29pm UTC](https://discourse.julialang.org/t/passing-a-struct-to-a-function-allocates-whereas-passing-an-array-does-not/103303/1 "2023-08-28T17:29:50Z")

</div>

Hi,

I noticed that the simple code `example_1!` below allocates memory (lots of it when this is embedded in a large loop) whereas `example_2!` does not.

1. `example_1!` takes the 3-dimenional array `conn[iel, :, :]` and, within a look, assigns its value to the scalar `m`.

2. `example_2!` takes the same array except that that array is an argument from a previously defined struct argument (mesh.conn[iel, :,:]) and is also assigned to the scalar `m`.

I can’t understand why `example_1!` allocates 2 orders of magnitude less than `example_2!`.

```julia
function example_1!(conn, iel)
    
    for l = 1:ngl, i = 1:mesh.ngl

                m = conn[iel, i, l]
    end

end

```

` 40.873 μs (400 allocations: 6.25 KiB)`

whereas:

```julia
function example_2!(st_mesh, iel)
    
    for l = 1:ngl, i = 1:mesh.ngl
    
                m = st_mesh.conn[iel, i, l]
    end

end

```

` 1.348 ms (41825 allocations: 653.52 KiB)`

The minimal version of the struct is:

```julia
Base.@kwdef mutable struct St_mesh{TInt, TFloat}
       conn = Array{Int64}(undef, 0)

       ngl::Union{TInt, Missing} = 4 #this is used defined and is changed later
end

```

where `conn` is allocated with the call:  
` mesh.conn = Array{Int64}(undef, mesh.nelem, mesh.ngl, mesh.ngl)`  
where  
`mesh = St_mesh{TInt,TFloat}(ngl)`

---

<div class="post-metadata">

### Author: ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)
#### Post date: [August 28, 2023, 5:58pm UTC](https://discourse.julialang.org/t/passing-a-struct-to-a-function-allocates-whereas-passing-an-array-does-not/103303/2 "2023-08-28T17:58:54Z")

</div>

When you passed an array directly in `example_1!`, it knew exactly what `conn` was because it knew it was passed an `Array{Int64,3}` so it didn’t have this problem. In `example_2!`, it knew that it got a `St_mesh`, but it couldn’t know (from the type `St_mesh{TInt,TFloat}`) what the `.conn` field was. This can be seen from

```julia
julia> fieldtypes(St_mesh{Int64,Float32})
(Any, Union{Missing, Int64})

```

Notice that the first field of your struct is not concretely typed (it’s `Any`). This means that any time the program looks at `st_mesh.conn`, [it has no idea what it’s going to find](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-fields-with-abstract-type). The surrounding code must be compiled to be ultra-generic. This causes it to be slow and allocating.

Try changing the definition of `conn` in your `St_mesh` struct definition to something concrete like `conn::Array{Int64,3} = zeros(Int64,0,0,0)`.

---

<div class="post-metadata">

### Author: ![simon79](https://avatars.discourse-cdn.com/v4/letter/s/76d3ee/32.png) [@simon79](https://discourse.julialang.org/u/simon79)
#### Post date: [August 28, 2023, 6:08pm UTC](https://discourse.julialang.org/t/passing-a-struct-to-a-function-allocates-whereas-passing-an-array-does-not/103303/3 "2023-08-28T18:08:01Z")

</div>

@mikmoore indeed that solved it. Thank you.
