# Specificity of binary method with diagonal type specification for dispatch

I am having trouble understanding why the following code does not dispatch on `Base.convert(::Type{T}, ::T)` as I would expect:

``````abstract type SuperType end

struct MyType{T} <: SuperType end

function Base.convert(::Type{<:MyType}, t::SuperType)
println("Converting")
MyType{Int}()
end

convert(MyType{Int32}, MyType{Int32}())
# goes through the `convert` method we just added instead of `Base.convert(::Type{T}, ::T)`
``````

Is there a reason for this behavior? It forces me to define `Base.convert(::Type{T}, t::T) where {T<:SuperType} = t` for the code to avoid bugs that rely on this invariant.

1 Like

I second this question. Appreciate if someone can clarify what is happening here.

This behavior seems reasonable to me. The `Base.convert(::Type{<:MyType}, t::SuperType)` method that you defined is more specific than the `Base.convert(::Type{T}, ::T)` method. The general rule is that when two methods are both applicable, the more specific method is the one that will be called.

In fact, the `Base.convert` method that you defined explicitly contradicts the invariant that you’re trying to maintain. So you could define something like this instead:

``````function Base.convert(::Type{S}, x::T) where {S <: MyType, T <: SuperType}
println("Converting")
if S == T
x
else
MyType{Int}()
end
end
``````

However, that still seems goofy, because then you have

``````convert(MyType{Int32}, MyType{Int8}()) == MyType{Int64}
``````

which violates the invariant that `typeof(convert(T, x)) == T`.

What exactly is it that you are trying to achieve with your new `convert` method?

Unfortunately the rules for method specificity are not given in the Julia manual. I think the details are rather complicated, so the developers do not want to codify a list of specificity rules by putting them in the manual. There’s a brief discussion of method specificity in the developer docs:

https://docs.julialang.org/en/v1/devdocs/types/#Subtyping-and-method-sorting

Also take a look at this video:

Thanks for your answers. I would have expected that the diagonal type specification (having `(::Type{T}, ::T) where {T}`) would have been more specific over anything else (unless a similar method whose `T` is further constrained was defined of course).

What the `convert` method does is not important, I admit that in this example it may not make much sense. In your code snippet, the line `if S == T` is the equivalent of `Base.convert(::Type{T}, t::T) where {T<:SuperType} = t` I mentioned above. I would have preferred to avoid any of both, but I guess this is just a corner case that is not so intuitive for method specificity rules.

I think subtype relationships have the highest priority when it comes to method specificity. Diagonal type restrictions are farther down on the list.

In your actual use case, are you defining a `convert` method, or is it some other function? Just wondering, because usually if you encounter a method error for `convert`, it doesn’t mean that you should implement a `convert` method—it means that you are doing something wrong further up the chain. 1 Like

I see, it makes sense, thanks.

It is indeed about a `convert` method, which actually might be better specified with the form

``````Base.convert(::Type{MyType}, t::SuperType)
``````

``````Base.convert(::Type{<:MyType}, t::SuperType)