# Help to avoid a type-instability

**URL:** <https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097>\
**Category:** General Usage\
**Created:** [February 3, 2020, 12:16am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097 "2020-02-03T00:16:47Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 12:16am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/1 "2020-02-03T00:16:47Z")

</div>

Hi!

I need to construct a struct that has a vector with elements of another structure as in this code:

```julia
mutable struct A{T}
    value::T
end

mutable struct B
    v::Vector{A}
end

get_data(a::A{T}) where T = a.value
get_data(b::B) = get_data.(b.v)

a1 = A(1)
a2 = A(true)
a3 = A(1.0)

b = B([a1,a2,a3])

```

Of course, `get_data` in elements from `A` are type stable:

```julia
julia> @code_warntype get_data(a1)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  a::A{Int64}

Body::Int64
1 ─ %1 = ^[[A^[[DBase.getproperty(a, :value)::Int64
└── return %1

julia> @code_warntype get_data(a2)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  a::A{Bool}

Body::Bool
1 ─ %1 = Base.getproperty(a, :value)::Bool
└── return %1

julia> @code_warntype get_data(a3)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  a::A{Float64}

Body::Float64
1 ─ %1 = Base.getproperty(a, :value)::Float64
└── return %1

```

However, `get_data` in elements from `B` is not:

```julia
julia> @code_warntype get_data(b)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  b::B

Body::Union{BitArray{1}, Array}
1 ─ %1 = Base.getproperty(b, :v)::Array{A,1}
│ %2 = Base.broadcasted(Main.get_data, %1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(get_data),Tuple{Array{A,1}}}
│ %3 = Base.materialize(%2)::Union{BitArray{1}, Array}
└── return %3

```

This is leading to a huge performance hit in my original code. Can anyone help me to avoid this type-instability?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [February 3, 2020, 12:26am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/2 "2020-02-03T00:26:11Z")

</div>

> [@Ronis\_BR](#):
>
> Can anyone help me to avoid this type-instability?

Use `A` as parameter of `B`?

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 12:27am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/3 "2020-02-03T00:27:31Z")

</div>

But the vector `v` in `B` can have an arbitrary number of `A`s with different types. Like `v = [A{Int}, A{Bool}, A{Float64}]`. Thus, I have no idea how to do this.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [February 3, 2020, 12:45am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/4 "2020-02-03T00:45:40Z")

</div>

How many different types can hold `A`?

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 12:47am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/5 "2020-02-03T00:47:43Z")

</div>

Well, infinite. Because it can also hold user-defined structures.

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [February 3, 2020, 12:55am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/6 "2020-02-03T00:55:38Z")

</div>

What about using `map(get_data,b.v)`? as far as I know, map creates an array and widens the array type to hold the elements on demand, resorting to `Any` as a fallback

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 1:01am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/7 "2020-02-03T01:01:47Z")

</div>

I still get the type instability, even if all the elements in `v` are of the same type:

```julia
julia> @code_warntype get_data(b)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  b::B

Body::Array{_A,1} where _A
1 ─ %1 = Base.getproperty(b, :v)::Array{A,1}
│ %2 = Main.map(Main.get_data, %1)::Array{_A,1} where _A
└── return %2

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [February 3, 2020, 1:07am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/8 "2020-02-03T01:07:22Z")

</div>

> [@Ronis\_BR](#):
>
> I still get the type instability, even if all the elements in `v` are of the same type:

Not if `B` has `A` as parameter:

```julia
julia> b
B{A{Int64}}(A{Int64}[A{Int64}(1), A{Int64}(2), A{Int64}(3)])

julia> @code_warntype get_data(b)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  b::B{A{Int64}}

Body::Array{Int64,1}
1 ─ %1 = Base.getproperty(b, :v)::Array{A{Int64},1}
│ %2 = Base.broadcasted(Main.get_data, %1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(get_data),Tuple{Array{A{Int64},1}}}
│ %3 = Base.materialize(%2)::Array{Int64,1}
└── return %3

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [February 3, 2020, 1:10am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/9 "2020-02-03T01:10:18Z")

</div>

Also, it probably doesn’t affect type-stability, but does `B` need to be mutable?

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 1:14am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/10 "2020-02-03T01:14:02Z")

</div>

But how can I do that when `v` can have for example `[A{Int64}, A{Bool}, A{Float64}]`?

> [@giordano](#):
>
> but does `B` need to be mutable?

In this example no, but in my original code yes.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [February 3, 2020, 1:24am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/11 "2020-02-03T01:24:28Z")

</div>

> [@Ronis\_BR](#):
>
> But how can I do that when `v` can have for example `[A{Int64}, A{Bool}, A{Float64}]` ?

If you want the freedom of having inhomogeneous vectors with any types, then type-instabilities are probably unavoidable

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 1:25am UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/12 "2020-02-03T01:25:49Z")

</div>

OK thanks! I though if I knew the type of all the elements in the vector at compile type, then I could make some tuple or something to avoid the type instability.

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 1:33pm UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/13 "2020-02-03T13:33:03Z")

</div>

After this discussion, it seems that it can be improved. We have a way to make this type stable by changing the `v` to a `Tuple` is two conditions:

- The number of elements in `v` is fixed; or
- The types of elements in `v` are equal.

Thus, I think we can improve by having something like `Vararg` that can define a number of different types 🙂

I am not expert and perhaps this is impossible. However, I opened a issue in Github to discuss this further:

[https://github.com/JuliaLang/julia/issues/34640](https://github.com/JuliaLang/julia/issues/34640)

---

<div class="post-metadata">

**Author:** ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)\
**Post date:** [February 3, 2020, 2:01pm UTC](https://discourse.julialang.org/t/help-to-avoid-a-type-instability/34097/14 "2020-02-03T14:01:42Z")

</div>

Using @kristoffer.carlsson with @giordano I could solve this problem:

```julia
mutable struct A{T}
    value::T
end

mutable struct B{V <: Tuple}
    v::V
end

get_data(a::A{T}) where T = a.value
get_data(b::B) = map(get_data,b.v)

a1 = A(1)
a2 = A(true)
a3 = A(1.0)

b = B((a1,a2,a3))

```

```julia
julia> @code_warntype get_data(b)
Variables
  #self#::Core.Compiler.Const(get_data, false)
  b::B{Tuple{A{Int64},A{Bool},A{Float64}}}

Body::Tuple{Int64,Bool,Float64}
1 ─ %1 = Base.getproperty(b, :v)::Tuple{A{Int64},A{Bool},A{Float64}}
│ %2 = Main.map(Main.get_data, %1)::Tuple{Int64,Bool,Float64}
└── return %2

```

Thanks for the help!
