List of elements with unknown type, is it bad?

Hi,

I have a project where I need to append to a result list, several objects depending on conditions. A MWE is presented in the following code. In practice, I have more subtypes of ABS (like ~10). I would like foo to be the most efficient (fastest).

To me, the type of res is not known and so foo is not efficient. I tend to think that a different structure is needed to handle this situation. However, I noticed:

Surprisingly to me, using @code_warntype does not reveal type unstability.

Hence:

  • is it the best way to handle this situation?
  • should I enforce res = Vector{Union{A{T},B{T},C{T}}(undef, 0)? (and later with 10s of subtypes?)
  • should I leave it like that?

Thank you for your help,

using Revise

abstract type ABS end
struct A{T} <: ABS ;a::T;end
struct B{T} <: ABS ;b::T;end
struct C{T} <: ABS ;b::T;end

function foo(x::T) where T
	res = Vector(undef, 0)
	push!(res, A(x))
	push!(res, B(x))
	for i=1:13
		r = rand(T)
		if r < 0.25
			push!(res, A(r))
		elseif r<0.75
			push!(res, B(r))
		else
			push!(res, C(r))
		end
	end
	res
end
	foo(1.2)

If I understand correctly you did something like @code_warntype foo(1.2), right? Well, this by itself is not type-unstable. The returned value is always a Vector{Any} (that is a concrete type), so the “function itself” is type-stable. What is type-unstable is dealing with values obtained from the Vector:

julia> a = foo(1.2);
julia> @code_warntype a[rand(1:15)]
Variables
  #self#::Core.Compiler.Const(getindex, false)
  A::Array{Any,1}
  i1::Int64

Body::Any
1 ─ %1 = Base.arrayref($(Expr(:boundscheck)), A, i1)::Any
└──      return %1

Because then, the type returned is Any (not Vector{Any}) and Any is the root abstract type, so this can be anything.

If you really need a dynamic number of elements of distinct type, there is not much else to do. If every element is a subtype of ABS then I would suggest changing the function first line to res = Vector{ABS}(undef, 0) to at least restrict the type a little. Accessing elements will be type unstable anyway (because ABS is an abstract type) but maybe the compiler can optimize one or other thing.

I suggest you look at this recent answer of mine about how to limit the damage cause by type-instability.

that is a concrete type

I add forgotten that. For me, Any is (was) bad.

I suggest you look at this recent answer of mine about how to limit the damage cause by type-instability.

Thanks

Where you will have performance problems is if later you want evaluate functions which take those elements of the array as parameters, and the functions will have to be dynamically dispatched at run time for every element of the array. The best alternative is to try to reorganize the data to avoid mixed-type arrays, but detailed discussions on that can be found in these threads:

(look particularly at Skoffer’s answers and the macro he provides in the third thread).

2 Likes