How to dispatch on a union of parametric types with partial Type-instruction?


#1

I have two types, MDI and ODEIntegrator. Both are parameterized with many types. However, for my dispatch purposes, I only care about the first of MDI and the second of ODEIntegrator. I can dispatch on them like:

# Version 1
test(integ::ODEIntegrator{Alg, S}) where{Alg, S<:SMatrix} = 1
test(integ::MDI{false}) = 1

# Version 2
test(integ::ODEIntegrator{Alg, S}, ws_index) where{Alg, S<:Matrix} = 2
test(integ::MDI{true}) = 2

The above works perfectly fine.

But now, I am really believing that I can achieve the same result with only 2 function definitions, by using Union. Unfortunately I think I have not understood how to use it, because I though that this:

function test(
    integ::Union{A, B}) where
    {A<:ODEIntegrator{Alg, S} where {Alg, S<:SMatrix}, B<:MDI{false}}
  1
end

function test(
    integ::Union{A, B}) where
    {A<:ODEIntegrator{Alg, S} where {Alg, S<:Matrix}, B<:MDI{true}}
  2
end

should be equivalent with the other definitions. However, when I try to call the method (without having defined the ones in the start of my post), Julia says that it cannot find any method that matches test with my object. Why?


#2

The current dispatch behavior in Julia v0.6 (and previous versions) requires that every parameter in a method signature must be given a value for the method to match. In your case, that means that whatever types you pass in must allow Julia to assign both the S and B parameters in the Union. Neither of your types does so (of course) so neither matches the signature.

Fortunately, this requirement is dropped in Julia v0.7, so I think your code should just work. Here’s a simpler example:

v0.6

julia> struct Foo{A}
       end

julia> struct Bar{B}
       end

julia> f(::Union{Foo{A}, Bar{B}}) where {A, B} = 1
f (generic function with 1 method)

julia> f(Foo{Int}())
ERROR: MethodError: no method matching f(::Foo{Int64})
Closest candidates are:
  f(::Union{Bar{B}, Foo{A}}) where {A, B} at REPL[3]:1

v0.7

julia> struct Foo{A}
       end

julia> struct Bar{B}
       end

julia> f(::Union{Foo{A}, Bar{B}}) where {A, B} = 1
f (generic function with 1 method)

julia> f(Foo{Int}())
1