# Method specificity gotcha

**URL:** <https://discourse.julialang.org/t/method-specificity-gotcha/10349>\
**Category:** Internals & Design\
**Created:** [April 15, 2018, 4:30am UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349 "2018-04-15T04:30:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 15, 2018, 4:30am UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349/1 "2018-04-15T04:30:56Z")

</div>

I just spent a lot of time debugging what came down to the following:

```julia
struct Foo{T<:Integer} end

f(::Type{F}) where {T, F<:Foo{T}} = 1
f(::Type{F}) where {F<:Foo} = 2

```

I expected `f(Foo{Int})` to return `1` and `f(Foo)` to return 2, yet

```julia
julia> f(Foo{Int})
2

julia> f(Foo)
2

```

If you remove the `<:Integer` constraint from the definition of `Foo`, `f(Foo{Int})` returns `1` as expected. Alternatively, replacing the first method of `f` with

```julia
f(::Type{F}) where {T<:Integer, F<:Foo{T}} = 1

```

also works as I expected.

Is this behavior desired? It was certainly surprising to me.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [April 15, 2018, 7:14am UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349/2 "2018-04-15T07:14:07Z")

</div>

Seems relevant:

```julia
julia> struct Foo{T<:Integer} end

julia> Foo <: (Foo{T} where T)
true

julia> (Foo{T} where T) <: Foo
false

julia> Foo <: (Foo{T} where T <: Integer)
true

julia> (Foo{T} where T <: Integer) <: Foo
true

```

```julia
julia> struct Foo{T} end

julia> Foo <: (Foo{T} where T)
true

julia> (Foo{T} where T) <: Foo
true

```

> [@tkoolen](#):
>
> If you remove the `<:Integer` constraint from the definition of `Foo`, `f(Foo{Int})` returns `1` as expected.

May I ask why is this expected? I think if you remove `<:Integer`, the 2 functions become semantically indistinguishable, not sure why Julia goes for one over the other, perhaps some subtle rule in the code?

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 15, 2018, 1:17pm UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349/3 "2018-04-15T13:17:07Z")

</div>

> [@mohamed82008](#):
>
> May I ask why is this expected? I think if you remove \<:Integer, the 2 functions become semantically indistinguishable, not sure why Julia goes for one over the other, perhaps some subtle rule in the code?

I mostly expected this from previous experience. Unfortunately, the documentation on method specificity could be better, [Wishlist: document method specificity rules · Issue #23740 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/23740). I do think it’s desired to have this behavior, since it can be quite useful to distinguish between `f(Foo)` and `f(Foo{SomeT})` for all `SomeT` without having to define a method for each possible `SomeT`: If `f` is called with e.g., `Foo{String}` or `Foo{Int}` as the argument, the user has supplied more information than when `f` is called with just `Foo` as the argument, and it should be possible to distinguish between these two cases using appropriate method definitions.

I think there are two options to make the behavior from my first post less surprising.

#### Option 1

The first option would be to have the first method

```julia
f(::Type{F}) where {T, F<:Foo{T}} = 1

```

be automatically interpreted as

```julia-auto
f(::Type{F}) where {T<:Integer, F<:Foo{T}} = 1

```

i.e., to deduce from the parameter bounds of `Foo` that `T` must always be `<:Integer` for the method to make sense. In general if `T` is a parameter of more than one type, perhaps this would need to be done using `typeintersect`.

#### Option 2

The other way would be to interpret the second signature,

```julia
f(::Type{F}) where {F<:Foo} = 2

```

so that it doesn’t have the implicit `<:Integer` constraint (due to the fact that `Foo === Foo{T} where T<:Integer`) and acts like

```julia
f(::Type{F}) where {F<:Foo{T} where T} = 2

```

(which is another way to get the behavior I expected).

I think option 1 would be more desirable (because the truth value of `Foo === Foo{T} where T<:Integer` should probably not be context-dependent). I suspect there may be practical reasons that make option 1 infeasible though, namely that `typeintersect(T, S)` is not guaranteed to produce the ‘smallest’ `R` such that `R<:T` and `R<:S`.

I guess option 3 would be to just acknowledge that this is a bit of a corner case and accept that you need to be more careful in such cases.

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [April 15, 2018, 7:06pm UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349/4 "2018-04-15T19:06:15Z")

</div>

This is a longstanding issue: [https://github.com/JuliaLang/julia/issues/6383](https://github.com/JuliaLang/julia/issues/6383)

I hope to try to implement your “option 1”; coming up with a way to automatically propagate the variable bounds is just tricky.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [April 15, 2018, 7:08pm UTC](https://discourse.julialang.org/t/method-specificity-gotcha/10349/5 "2018-04-15T19:08:34Z")

</div>

Good to hear! Thanks for the pointer.
