Question about the selection mechanism of multiple dispatch


#1

Hi guys!

I am having problems to understand the mechanism of multiple dispatch. The documentation has the following text:

When a function is applied to a particular tuple of arguments, the most specific method applicable to those arguments is applied. Thus, the overall behavior of a function is a patchwork of the behaviors of its various method definitions. If the patchwork is well designed, even though the implementations of the methods may be quite different, the outward behavior of the function will appear seamless and consistent.

However, let me see if I understood correctly.

Let’s say I have the following type:

T_ECIs = Union{Type{Val{:GCRF}},
               Type{Val{:J2000}},
               Type{Val{:TOD}},
               Type{Val{:MOD}},
               Type{Val{:TEME}}}

And then I defined the two following functions:

function rECItoECI(T_ECIo::T_ECIs, T_ECId::T_ECIs, JD_UTC::Number)
...
end
function rECItoECI(T_ECIo::Type{Val{:TEME}}, T_ECId::Type{Val{:TEME}}, JD_UTC::Number)
...
end

In a simplified example, I saw that if I call rECItoECI(Val{:TEME}, Val{:TEME}, 0) then the second function is selected. However, is it assured that this will always happen? I think I am confusing what “most specific method” means.


#2

Well, somebody could later add a method such as:

function rECItoECI(T_ECIo::Type{Val{:TEME}}, T_ECId::Type{Val{:TEME}}, JD_UTC::Integer)
...

which would be more specific that with JD_UTC::Number,
so the dispatch would go to that method instance.


#3

Thanks!

But without this definition, the second one will always be called right?


#4

Yes. A type T is always more specific than Union{T, X} for some other type X, so a method defined with ::T as its argument will be more specific than one with ::Union{T, X} (assuming no change in the other arguments).

A few examples:

  • foo(::T) is more specific than foo(::Union{T, X})
  • foo(::T, ::X) is more specific than foo(::Union{T, X}, ::X)
  • foo(::T, ::X) is more specific than foo(::T, ::Union{T, X})
  • foo(::T, ::X) is more specific than foo(::Union{T, X}, ::Union{T, X})

But there are ambiguous cases:

  • foo(::Union{T, X}, ::X) is ambiguous with (neither more nor less specific than) foo(::T, ::Union{T, X})

If there is no unique most-specific method, then Julia will throw an ambiguity error, so there’s no need to worry about one method being arbitrarily preferred.