Dispatch on precice Union instance in place of subtyping supertype of Union

This is a bit tricky I feel, but I didn’t really found out how to separate the two cases.

I have an abstract type AbstractAgent. I have a model type which is parameterized on subtypes of my abstract type, see the following MWE:

abstract type AbstractAgent end

struct ABM{A<:AbstractAgent}
end

struct A <: AbstractAgent
end

model1 = ABM{A}()

struct B <: AbstractAgent
end

struct C <: AbstractAgent
end

model2 = ABM{Union{A, B, C}}()

I have a function which I want to make a dispatch on whether the type A contained in ABM is concrete or a Union (I am really targeting unions of concrete types, if that is even possible).

I wrote:

step!(model::ABM) = println("generic")

step!(model::ABM{A}) where {A<:Union} = println("on union")

step!(model1)
step!(model2)

However they both print generic, pressumably becase t A as well as Union{A, B, C} are subtypes of AbstractAgent. How can I achieve the dispatch rule I want…?

Maybe this will avoid dispatch of the Unions as generics?

step!(model::ABM{T}) where T<: AbstractAgent = println("generic")

Nope, this doesn’t change anything, even if I do not define the method step!(model::ABM) = println("generic") at all, and use your suggestion, both calls still yield generic.

I am not sure if I understand. But it seems that a REPL restart is needed here to remove previous definitions

I’ve done a REPL restart. Your suggestion does not alter the outcome. This is because Union{A, B, C} <: AbstractAgent is true.

1 Like

Indeed. Not a solution, but maybe a reflection. Given the similar relationship

Union{Int32, Int64} <: Integer = true

One variable instance can be either one type or the other, so it doesn’t make sense to define a method that is specific for Union types. Except that the variable is a container with more than one value, in which case the dispatch should be on the type of the container.

What you can do is the contrary of being generic:

julia> not_generic_step!(model) = println("not generic")
not_generic_step! (generic function with 1 method)

julia> step!(model::ABM{A}) = not_generic_step!(model)
step! (generic function with 4 methods)

julia> step!(model::ABM{B}) = not_generic_step!(model)
step! (generic function with 5 methods)

julia> step!(model) = println("generic")
step! (generic function with 3 methods)

julia> step!(model1)
not generic

julia> step!(model2)
generic

1 Like

This should work:

function step!(m::ABM{T}) where T
    if T isa Union
        println("for unions")
    else
        println("generic")
    end
end

But I agree with @lmiq that this is an unusual paradigm…

1 Like

Yeah that works. I was hoping I could avoid if statements and only use directly multiple dispatch but I guess it is not possible…