Runtime dispatch in struct that contains struct

Hi, in my code, I have a structure similar to the below. The function that I call in running should be determined by FooContainer.foo, so it is clear to me that I have runtime dispatch here. What is the idiomatic way to work around this runtime dispatch here? I would guess that using one method for run_foo in which I check the type of foo, e.g. using isa(foo, Foo1) resolves the problem, but is this the preferred solution? In reality, I’ll have a few (5-10) subtypes of FooType and would like to dispatch on x, which may have various types (say vector, matrix, float etc.), so I want to make sure that I get the right approach here…

using JET

abstract type FooType end

struct Foo1 <: FooType end 
struct Foo2 <: FooType end

struct FooContainer 
    foo::FooType
end

function run_foo(foo::Foo1, x::Float64)
    return x
end

function run_foo(foo::Foo2, x::Float64)
    return x^2
end

function running(foo_container::FooContainer, x::Float64)
    return run_foo(foo_container.foo, x)
end

rep = @report_opt running(FooContainer(Foo1()), 2.0)
show(rep)

which returns

═════ 1 possible error found ═════
┌ running(foo_container::FooContainer, x::Float64) @ (HIDDEN)
│ runtime dispatch detected: run_foo(%1::FooType, x::Float64)::Float64

Here.
You need to fully parameterize the FooContainer type. As of now, the FooContainer type can hold any type that is of FooType as foo.

1 Like

See the performance tips: avoid fields with abstract type.

1 Like

I see, thank you! So if I simply parametrise the type here, I should be fine? That would be very nice! I’ll check once I have time and mark this as the solution afterwards!

Is there some tooling that automatically identifies such issues? (under-parametrised types?)

Yes.

It really depends. Generally speaking, you’ll probably want

Just to expand on this, you’ll only be okay if the compiler can know ahead of time what the parameter is.

For example, if you have a vector with FooContainers that have many different FooTypes inside of them, then paramerizing wont help at all.

In cases like that, I would instead recommend an approach like SumTypes.jl or Moshi.jl.

These packages specialize in taking situations where you have a finite number of options and writing code that handles each of those options in a more efficient way than dispatch can. There’s tradeoffs like a lack of extensibility, but the advantages can be quite nice too.