# Type stability with a vector of abstracts inside struct

**URL:** <https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353>\
**Category:** Performance\
**Tags:** type, struct, type-stability\
**Created:** [October 27, 2019, 4:18am UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353 "2019-10-27T04:18:03Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![abelsiqueira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abelsiqueira/32/47269_2.png) [@abelsiqueira](https://discourse.julialang.org/u/abelsiqueira)\
**Post date:** [October 27, 2019, 4:18am UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/1 "2019-10-27T04:18:03Z")

</div>

Hi all, I appreciate any help in making the following code type stable:

```julia
abstract type Something{T} end
Base.eltype(:: Something{T}) where T = T

mutable struct OneThing{T} <: Something{T}
  α :: T
end

# HERE
mutable struct ManyThings{T} <: Something{T}
  L :: Vector{Something}
end

# OR HERE
function ManyThings(L :: Vector{<: Something})
  T = promote_type(eltype.(L)...)
  ManyThings{T}(L)
end

function test()
  A = OneThing(2.0)
  B = OneThing(3)
  S = ManyThings([A, B])
  @code_warntype ManyThings([A, B])
end

test()

```

output:

```julia
┌ Info: 
└ eltype(S) = Float64
Variables
  #self#::Type{ManyThings}
  L::Array{OneThing,1}
  T::Any

Body::ManyThings{_A} where _A
1 ─ %1 = Base.broadcasted(Main.eltype, L)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(eltype),Tuple{Array{OneThing,1}}}
│ %2 = Base.materialize(%1)::Any
│ (T = Core._apply(Main.promote_type, %2))
│ %4 = Core.apply_type(Main.ManyThings, T)::Type{ManyThings{_A}} where _A
│ %5 = (%4)(L)::ManyThings{_A} where _A
└── return %5

```

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 27, 2019, 5:45am UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/2 "2019-10-27T05:45:29Z")

</div>

I am not sure what you want here: the `L` field of a `ManyThings` is not a concrete type, so how could the compiler infer more?

Also, note that `eltype` should be defined on _types_, not values.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [October 27, 2019, 11:27am UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/3 "2019-10-27T11:27:21Z")

</div>

`Vector{Something}` is not a concrete type, `Vector{S} where S<:Something{T}` would be. That would require the change of `ManyThings` parameters to `ManyThings{T, S<:Something{T}}`.  
Another question: why is `ManyThings` mutable? Having a container as a single field sort of implies that you want to change the contents of said container, not re-bind `L` to something else.

---

<div class="post-metadata">

**Author:** ![abelsiqueira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abelsiqueira/32/47269_2.png) [@abelsiqueira](https://discourse.julialang.org/u/abelsiqueira)\
**Post date:** [October 27, 2019, 1:49pm UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/4 "2019-10-27T13:49:42Z")

</div>

Thanks for the replies.

@Tamas_Papp, my objective is to change `ManyThings` so that the compiler can infer more.  
I changed `eltype` to `eltype(:: Type{<: Something{T}}) = where T = T`, is that the right way to do it?

@Vasily_Pisarev, there are two problems with `Vector{S}`: I can’t have `S <: Something{T}` because the element types are not the same (in the example, one is `Float64`, the other is `Int`). And if I only have `S <: Something`, then `S` is also not inferred. This is essentially the problem, I can’t have a concrete type for `S`, since `promote_type(OneThing{Float64}, OneThing{Int}) = OneThing`. Regarding `mutable`, it was a mistake on my part.

I got the following to be type stable, but I can’t extend it:

```julia
struct TwoThings{T,S,Q} <: Something{T}
  A :: S
  B :: Q
end

function TwoThings(A :: Something, B:: Something)
  T = promote_type(eltype(A), eltype(B))
  TwoThings{T,typeof(A),typeof(B)}(A, B)
end

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 27, 2019, 2:06pm UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/5 "2019-10-27T14:06:06Z")

</div>

Yes, that’s how you define `eltype`.

You may want something like

```julia
mutable struct ManyThings{T} <: Something{T}
    L::Vector{Something{T}} # note T
end

```

but it is hard to be sure from your problem description. Cf

[https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-fields-with-abstract-type-1](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-fields-with-abstract-type-1)

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [October 27, 2019, 3:22pm UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/6 "2019-10-27T15:22:03Z")

</div>

You can define a custom promote and conversion rules like

```julia
Base.promote_rule(::Type{OneThing{T}}, ::Type{OneThing{S}}) where {T,S} = OneThing{promote_type(T, S)}

Base.convert(::Type{OneThing{T}}, x::OneThing{S}) where {T,S} = OneThing{T}(x.α)

Base.convert(::Type{OneThing{T}}, x::OneThing{T}) where T = x

```

if that suits your use case.  
Of course, that would put `OneThing(3.0)` instead of the original `OneThing(3)` into `ManyThings`.  
But once you put things into a container with an abstract element type, you lose the type stability, that’s inevitable.

---

<div class="post-metadata">

**Author:** ![abelsiqueira](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abelsiqueira/32/47269_2.png) [@abelsiqueira](https://discourse.julialang.org/u/abelsiqueira)\
**Post date:** [October 27, 2019, 7:57pm UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/7 "2019-10-27T19:57:17Z")

</div>

Thanks, that makes sense. I think I’ll have to leave it type unstable, because my use case is a little more complicated (for instance, I have several other things `<: Something{T}`, and there is no clear way to promote them). If that slows down the code too much, I’ll take a second look.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 28, 2019, 4:32am UTC](https://discourse.julialang.org/t/type-stability-with-a-vector-of-abstracts-inside-struct/30353/8 "2019-10-28T04:32:31Z")

</div>

You can still use function barriers:

[https://docs.julialang.org/en/v1/manual/performance-tips/#kernel-functions-1](https://docs.julialang.org/en/v1/manual/performance-tips/#kernel-functions-1)
