# Specificity of binary method with diagonal type specification for dispatch

**URL:** <https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281>\
**Category:** General Usage\
**Tags:** question\
**Created:** [October 24, 2021, 8:37am UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281 "2021-10-24T08:37:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![serenity4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/serenity4/32/44707_2.png) [@serenity4](https://discourse.julialang.org/u/serenity4)\
**Post date:** [October 24, 2021, 8:37am UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/1 "2021-10-24T08:37:40Z")

</div>

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

```julia
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.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [October 25, 2021, 10:25am UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/2 "2021-10-25T10:25:21Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 25, 2021, 1:54pm UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/3 "2021-10-25T13:54:35Z")

</div>

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:

```julia
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

```julia
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?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 25, 2021, 2:18pm UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/4 "2021-10-25T14:18:55Z")

</div>

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](https://docs.julialang.org/en/v1/devdocs/types/#Subtyping-and-method-sorting)

Also take a look at this video:

[![](https://global.discourse-cdn.com/julialang/original/3X/1/d/1d5c5567a3f6004a6c9852f4fb8e89eb97fe67be.jpeg "JuliaCon 2019 | What's Bad About Julia | Jeff Bezanson") ](https://www.youtube.com/watch?v=TPuJsgyu87U)

---

<div class="post-metadata">

**Author:** ![serenity4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/serenity4/32/44707_2.png) [@serenity4](https://discourse.julialang.org/u/serenity4)\
**Post date:** [October 25, 2021, 5:50pm UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/5 "2021-10-25T17:50:05Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 25, 2021, 6:09pm UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/6 "2021-10-25T18:09:11Z")

</div>

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. 🙂

---

<div class="post-metadata">

**Author:** ![serenity4](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/serenity4/32/44707_2.png) [@serenity4](https://discourse.julialang.org/u/serenity4)\
**Post date:** [October 25, 2021, 6:31pm UTC](https://discourse.julialang.org/t/specificity-of-binary-method-with-diagonal-type-specification-for-dispatch/70281/7 "2021-10-25T18:31:39Z")

</div>

I see, it makes sense, thanks.

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

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

```

instead of

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

```

which removes the issue.
