# Defining types of Structs attributes can sometimes be negatively impacting performance?

**URL:** <https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823>\
**Category:** General Usage\
**Created:** [July 9, 2024, 1:25pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823 "2024-07-09T13:25:07Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [July 9, 2024, 1:25pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/1 "2024-07-09T13:25:07Z")

</div>

```julia
mutable struct Type4
    c
    a
    b
    function Type4(x=1,y=1,z=1)
        new(x,y,z)
    end
end

mutable struct Type5
    a
    b
    c
    function Type5(x::Int64=1, y::Int64=1, z::Int64=1)
        new(x,y,z)
    end
end

mutable struct Type8
    a::Real
    b::Real
    c::Real
    function Type8(x=1,y=1,z=1)
        new(x,y,z)
    end
end

mutable struct Type9
    a::Real
    b::Real
    c::Real
    function Type9(x::Int64=1,y::Int64=1,z::Int64=1)
        new(x,y,z)
    end
end

using BenchmarkTools
@benchmark Type4()
@benchmark Type5()
@benchmark Type8()
@benchmark Type9()

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/0/b0ba306cd88c6d9764c28af59ae10a61c4b143c4.png)

Not a huge difference but consistent difference.

```julia
@kwdef mutable struct Type10
    a::Real=1
    b::Real=1
    c::Real=1
end

mutable struct Type11
    a
    b
    c
    function Type11(x::Real=1, y::Real=1, z::Real=1)
        new(x,y,z)
    end
    function Type11(x::Number, y::Number,z::Number)
        new(x,y,z)
    end
end

mutable struct Type12
    a::Number
    b::Number
    c::Number
    function Type12(x::Real=1, y::Real=1, z::Real=1)
        new(x,y,z)
    end
    function Type12(x::Number, y::Number,z::Number)
        new(x,y,z)
    end
end

@benchmark Type10()
@benchmark Type11()
@benchmark Type12()

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/d/c/dc7642ea0df11a81273a4c8b3a4edc9fb36f7e1f.png)

To me, it seemed like not defining attribute types while defining the struct attributes, but later in the constructor is the best approach.

(Forgive me for my lingo… I am not well acquainted with the actual terminology we use and am still a beginner.)

---

<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:** [July 9, 2024, 1:32pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/2 "2024-07-09T13:32:25Z")

</div>

I don´t think those differences in performance are meaningful. But, for performance, what you need is to make the fields of the structs concrete. `Real`, for example, is an abstract type (it can be an integer, a float, etc).

You need either something like:

```julia
struct A
    x::Int
    y::Float64
end

```

where all the fields are concretely typed to specific types, or

```julia
struct A{T1<:Real,T2<:Real}
    x::T1
    y::T2
end

```

where an instance of the struct will have concrete types, but those can be of different types and different subypes of real.

Or some variation of the above constructs, always taking care that the fields are all concretely typed.

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [July 9, 2024, 1:36pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/3 "2024-07-09T13:36:43Z")

</div>

wait… so using `<:Real` is better than just `Real`?

So whether you define the types in constructors or the actual definition is meaningless eh? (As long as you ARE defining some type to help Julia figure out what functions to dispatch)

---

<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:** [July 9, 2024, 1:45pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/4 "2024-07-09T13:45:51Z")

</div>

> [@Maddy](#):
>
> So whether you define the types in constructors or the actual definition is meaningless eh?

Both are important. The declared type in the struct definition is more important, though.

---

<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:** [July 9, 2024, 1:46pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/5 "2024-07-09T13:46:45Z")

</div>

> [@Maddy](#):
>
> wait… so using `<:Real` is better than just `Real`?

The difference is having that directly on the structure field, as you did, or as a type parameter, as I did. If you set the field to be Real, you are saying that the field can be changed from one type to the other in the same instance of the struct:

```julia-repl
julia> mutable struct A x::Real end

julia> a = A(1)
A(1)

julia> a.x = 1.3
1.3

```

When you use a parametric type, you can _initialize_ the structure with the subtypes, but then the structure has a concrete type associate with it:

```julia-repl
julia> mutable struct B{T<:Real} x::T end

julia> b = B(1)
B{Int64}(1)

julia> b.x = 1.3
ERROR: InexactError: Int64(1.3)

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [July 9, 2024, 2:02pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/6 "2024-07-09T14:02:20Z")

</div>

> [@Maddy](#):
>
> As long as you ARE defining some type to help Julia figure out what functions to dispatch

Of note is that the declared field type has _no bearing_ on the dispatch behavior of a value retrieved from that field. For example:

```julia
julia> struct Foo
           a::Real
       end

julia> bar(::Real) = "Real fallback"
bar (generic function with 1 method)

julia> bar(::Int) = "Int specialization"
bar (generic function with 2 methods)

julia> bar(Foo(1).a)
"Int specialization"

julia> bar(Foo(1.0).a)
"Real fallback"

```

When you say a struct field has type `Real`, all you’re saying is “this field can hold objects of any subtype of `Real`”. Type inference will use that information to narrow down the possibilities for dispatching, but it won’t otherwise influence dispatch behavior.

One consequence of declaring a field with an abstract type is that the object actually stored there is no longer stored in-line, because the original type needs to be preserved for dynamic dispatch to work. It’s this indirection & dynamic type checks that cause a slowdown in hot loops.

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [July 9, 2024, 2:15pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/7 "2024-07-09T14:15:26Z")

</div>

Ahhhhhh I see!

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [July 9, 2024, 2:24pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/8 "2024-07-09T14:24:35Z")

</div>

> [@Maddy](#):
>
> To me, it seemed like not defining attribute types while defining the struct attributes, but later in the constructor is the best approach.

You are only timing the constructor. It could be there are some differences there, but they don’t seem to be significant.

The big performance difference is when you are using the struct. And the difference is whether the types of the fields are concrete or not.

```julia
struct MyStruct1
    x::Real
end

struct MyStruct2{T <: Real}
    x::T
end

```

Now, consider these calls:

```julia
f(arg) = 2arg.x

x1 = MyStruct1(2)
x2 = MyStruct2(2)

f(x1)
f(x2)

```

When `f(x1)` is about to be run, the compiler looks at the `f`, and at `x1`. Ok, the `x1` is of type `MyStruct1`, it has a field of type `Real`. I’ll compile a version of `f` for `MyStruct1`. It does, and figures out that `arg.x` should be multiplied by 2. But it doesn’t know the type of `arg.x`, only that it’s a `Real`. So instead of simple `mul` instruction it creates code for finding a multiply function for whatever type `arg.x` happens to be. It’ll take some hundreds of clock ticks.

On the other hand, the `f(x2)` is easier for the compiler. It sees that `x2` is of type `MyStruct2{Int}`. It compiles an instance of `f` for the type `MyStruct2{Int}`. It finds that the `2arg.x` is multiplying the `Int` `arg.x` by the `Int` 2. So the compiler emits a single `mul` instruction (or even just a left shift). The function takes at most a clock tick.

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [July 9, 2024, 4:54pm UTC](https://discourse.julialang.org/t/defining-types-of-structs-attributes-can-sometimes-be-negatively-impacting-performance/116823/9 "2024-07-09T16:54:31Z")

</div>

That makes it even more clear. Thank you!
