# Allocation during access to "typed" field of mutable struct

**URL:** <https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201>\
**Category:** Performance\
**Tags:** question\
**Created:** [February 28, 2021, 5:59pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201 "2021-02-28T17:59:15Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dilchatto](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilchatto/32/22393_2.png) [@Dilchatto](https://discourse.julialang.org/u/Dilchatto)\
**Post date:** [February 28, 2021, 5:59pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/1 "2021-02-28T17:59:16Z")

</div>

I have following struct

```julia
mutable struct Element{T<:AbstractElement} <: AbstractElement
    input::StringBuffer
    name::UnitRange{Int64}
    attributes::Union{Nothing, Attribute}
    value::Union{T, Nothing}
    parent::Union{Element, Nothing}
    next::Union{Element, Nothing}
end

```

```julia
Base.getindex(node::Element, key::AbstractString) = begin
    next = node.value
    while !isnothing(next)
        if _equals(getname(next), key) return next end
        next = getnext(next)
    end
    return error("no element with key: $key")
end

```

When I’m trying to access field **name** of the struct **Element** in function **getindex** using variable **next** there is 1 allocation (accessing any field except name does not cause allocations), but when I do it anywhere else it does not cause allocation. I don’t understand why accessing this field causes additional memory usage and how to fix this issue?

@code\_warn for this function provides the following results:

```julia
Variables
  #self#::Core.Compiler.Const(getindex, false)
  node::Element{Element{Element}}
  key::String
  next::Union{Nothing, Element}

Body::Union{Nothing, Element}
1 ─ (next = Base.getproperty(node, :value))
2 ┄ %2 = Main.isnothing(next)::Bool
│ %3 = !%2::Bool
└── goto #6 if not %3
3 ─ Base.getproperty(next, :name)
│ %6 = Main.getname(next)::StringView{UnsafeArray{UInt8,1}}
│ %7 = Main._equals(%6, key)::Bool
└── goto #5 if not %7
4 ─ return next
5 ─ (next = Main.getnext(next))
└── goto #2
6 ─ %12 = Base.string("no element with key: ", key)::String
│ Main.error(%12)
└── Core.Compiler.Const(:(return %13), false)

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [February 28, 2021, 6:04pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/2 "2021-02-28T18:04:21Z")

</div>

Please provide enough code so that the example is runnable for someone else.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 28, 2021, 6:10pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/3 "2021-02-28T18:10:20Z")

</div>

As Kristoffer said, it’s basically impossible to help here without more code. I was able to modify your provided code in order to define the `struct` and I observe no allocations in accessing the name field:

```julia
julia> abstract type AbstractElement end

julia> mutable struct Element{T<:AbstractElement} <: AbstractElement
           input::String
           name::UnitRange{Int64}
           attributes::Union{Nothing, Int}
           value::Union{T, Nothing}
           parent::Union{Element, Nothing}
           next::Union{Element, Nothing}
       end

julia> let e = Element{Element}("hi", 1:10, nothing, nothing, nothing, nothing)
           @btime $e.name
       end
  1.299 ns (0 allocations: 0 bytes)
1:10

```

I suspect the allocations are caused by something else. What could be causing those allocations though is anybody’s guess, since nobody but you knows how you defined `getname`, `getnext`, `_equals`, or `Attribute`.

---

<div class="post-metadata">

**Author:** ![Dilchatto](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilchatto/32/22393_2.png) [@Dilchatto](https://discourse.julialang.org/u/Dilchatto)\
**Post date:** [February 28, 2021, 6:26pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/4 "2021-02-28T18:26:42Z")

</div>

> [@Mason](#):
>
> `, nothing, nothing, nothing, nothing`

I’m sorry:

```julia
using Test
using BenchmarkTools

abstract type AbstractElement end

mutable struct Element{T<:AbstractElement} <: AbstractElement
           input::String
           name::UnitRange{Int64}
           attributes::Union{Nothing, Int}
           value::Union{T, Nothing}
           parent::Union{Element, Nothing}
           next::Union{Element, Nothing}
end

example(node::Element) = begin
    while !isnothing(node)
        if node.name == 1:1 return node end
        node = node.next
    end
    return error("error")
end

@testset "example" begin
    first = Element{Element}("", 2:2, nothing, nothing, nothing, nothing)
    second = Element{Element}("", 1:1, nothing, nothing, nothing, nothing)
    first.next = second
    @code_warntype example(first)
    @btime example($first)
end

```

You can just copypaste this snippet, it works and shows the problem

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 28, 2021, 8:19pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/5 "2021-02-28T20:19:19Z")

</div>

Ah, I see the problem now. This eluded me for a bit. The problem is that you’re using

```julia
::Union{Element, Nothing}

```

for the field `next`. This **looks** like a small union, but it’s actually not because `Element` is really `Element{T} where {T}`, a `UnionAll`!

Here’s a modified version of your code that doesn’t allocate and is two orders of magnitude faster:

```julia
abstract type AbstractElement end

mutable struct Element{T<:AbstractElement} <: AbstractElement
    input::String
    name::UnitRange{Int64}
    attributes::Union{Nothing, Int}
    value::Union{T, Nothing}
    parent::Union{Element{T}, Nothing}
    next::Union{Element{T}, Nothing}
end

example(node::Element) = begin
    while !isnothing(node)
        if node.name == 1:1 return node end
        node = node.next
    end
    return error("error")
end

first = Element{Element}("", 2:2, nothing, nothing, nothing, nothing)
second = Element{Element}("", 1:1, nothing, nothing, nothing, nothing)
first.next = second
@btime example($first)

```

```julia
#+RESULTS:
   3.110 ns (0 allocations: 0 bytes)
 Element{Element}("", 1:1, nothing, nothing, nothing, nothing)

```

---

<div class="post-metadata">

**Author:** ![Dilchatto](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilchatto/32/22393_2.png) [@Dilchatto](https://discourse.julialang.org/u/Dilchatto)\
**Post date:** [February 28, 2021, 8:26pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/6 "2021-02-28T20:26:29Z")

</div>

Thanks!!!  
Yeah, that was my misunderstanding of Julia typing. Switching from Java to Julia is a bit difficult))

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 28, 2021, 8:29pm UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/7 "2021-02-28T20:29:09Z")

</div>

So I actually didn’t need the extra information I requested earlier and if I was more perceptive, I could have noticed it right away. But having the code at least let me fiddle around until I stumbled upon the root problem

Yes, there can be lots of little performance gotchas like this when you get into type unstable code in Julia. I wish you the best of luck in the transition, I think you’ll find it’s worth your time!

How are you liking the language so far?

---

<div class="post-metadata">

**Author:** ![Dilchatto](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilchatto/32/22393_2.png) [@Dilchatto](https://discourse.julialang.org/u/Dilchatto)\
**Post date:** [March 1, 2021, 6:38am UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/8 "2021-03-01T06:38:29Z")

</div>

Actually, I would like to note 2 points: First, Julia allows write really high-performance code. Second, designing the code in Julia is a bit harder than in Java or Python due to absence of builtin interfaces. But, in general, it is very interesting language

---

<div class="post-metadata">

**Author:** ![moeddel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/moeddel/32/18641_2.png) [@moeddel](https://discourse.julialang.org/u/moeddel)\
**Post date:** [March 2, 2021, 10:46am UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/9 "2021-03-02T10:46:16Z")

</div>

> [@Dilchatto](#):
>
> Second, designing the code in Julia is a bit harder than in Java or Python due to absence of builtin interfaces. But, in general, it is very interesting language

Actually, there is a collection of informal interfaces in Julia. These are documented [here](https://docs.julialang.org/en/v1/manual/interfaces/).

---

<div class="post-metadata">

**Author:** ![Nikos\_Gianniotis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nikos_gianniotis/32/11487_2.png) [@Nikos\_Gianniotis](https://discourse.julialang.org/u/Nikos_Gianniotis)\
**Post date:** [November 18, 2021, 8:33am UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/10 "2021-11-18T08:33:26Z")

</div>

I have a very similar issue that I think fits with what the OP is saying, so I will post here instead of starting a new thread (obviously feel free to tell me that I should move this to a new thread).

The problem has to do with seeing more allocations when accessing a function that is inside a struct than when using the same function directly. Please consider the following MWE. The function in question is `tanh`. In function `first()`, `tanh` is called directly. In function `second()` it is called from within struct `dummy`. Function `third()` is calls `tanh` from a struct where no type has been provided.

I hope the following code makes it clearer:

```julia
struct Dummy
  f::Function
end

struct DummyNoType
  f
end

function runme()

    a = randn(1000)

    dummy = Dummy(tanh)
    dummynotype = DummyNoType(tanh)

    v = 0.0

    function first()
        for i in 1:1000
            v += tanh(a[i])
        end
    end

    function second()
        for i in 1:1000
            v += dummy.f(a[i])
        end
    end

    function third()
        for i in 1:1000
            v += dummynotype.f(a[i])
        end
    end

    @time first()
    @time second()
    @time third()
end

```

If execute `run()` I get:

```julia
  0.000057 seconds (2.00 k allocations: 31.250 KiB) # called first()
  0.000081 seconds (3.00 k allocations: 46.875 KiB) # called second()
  0.000089 seconds (3.00 k allocations: 46.875 KiB) # called third()

```

Why does the call to `second()` result in more memory allocations? Thanks for reading this.

---

<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:** [November 18, 2021, 10:03am UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/11 "2021-11-18T10:03:05Z")

</div>

> [@Nikos\_Gianniotis](#):
>
> ```julia
> struct Dummy
> f::Function
> end
> 
> ```

Function is an abstract type. Use

```julia
struct Dummy{F}
  f::F
end

```

---

<div class="post-metadata">

**Author:** ![Nikos\_Gianniotis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nikos_gianniotis/32/11487_2.png) [@Nikos\_Gianniotis](https://discourse.julialang.org/u/Nikos_Gianniotis)\
**Post date:** [November 18, 2021, 11:16am UTC](https://discourse.julialang.org/t/allocation-during-access-to-typed-field-of-mutable-struct/56201/12 "2021-11-18T11:16:01Z")

</div>

That is the solution, thanks!
