If i have a vector of different objects it is inherently an abstract type. How can I still avoid runtime-dispatch when looping over it?
abstract type AbstractFoo end
mutable struct Foo1 <: AbstractFoo
k::Int
end
mutable struct Foo2 <: AbstractFoo
k::Int
end
function run!(f::Foo1, k)
f.k = k * 1
return f
end
function run!(f::Foo2, k)
f.k = k * 2
return f
end
struct Container
items::Vector{<:AbstractFoo}
end
get_order(cnt::Container) = 1:length(cnt.items)
cnt = Container([Foo1(0), Foo2(0)])
function run!(cnt::Container, n::Int=1e6)
idx = get_order(cnt)
for k in 1:n
for i in idx
run!(c[i], k)
end
end
end
run!(cnt)
With @profview I see runtime-dispatch for run. Not sure if It happens in this example. Can I avoid it? Should I?
Well dynamic dispatch happens when the compiler cannot infer which method to call because some type is not known. I think it reasonable to see why this happens here - essentially you constructes the MWE to demonstrate that.
So either you change your approach fundamentally to avoid the abstractly typed container or you perform the dispatch yourself in code. The latter is done for you by WrappedUnions.jl.
Use Vector{Union{Foo1, Foo2}} instead of Vector{<:AbstractFoo} for Container. This will work well enough if you don’t have many types (less than 5 I think).
Wrap your Union of types and create branches which forces type stability (this is done automatically by WrappedUnions.jl as @abraemer said).
New option which I’m fond of: use the ECS pattern instead of a container of different types. The question is actually though if your problem is well-suited for this kind of systems. If so, this is the most performant and flexible option for programs with heterogeneous types in my opinion, but it requires some point of view changes. See GitHub - ark-ecs/Ark.jl: Archetype-based Entity Component System (ECS) for Julia. for that.