# Strange MethodError ambiguity

**URL:** <https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779>\
**Category:** General Usage\
**Tags:** question\
**Created:** [May 19, 2020, 9:32pm UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779 "2020-05-19T21:32:08Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bigorneau](https://avatars.discourse-cdn.com/v4/letter/b/4491bb/32.png) [@Bigorneau](https://discourse.julialang.org/u/Bigorneau)\
**Post date:** [May 19, 2020, 9:32pm UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/1 "2020-05-19T21:32:08Z")

</div>

I found a strange `MethodError` in my code. It is possible to reproduce it with the following simple code

> `struct A{T} x::T end`  
> `fun(a::A{T}, b::T) where {T} = "same parametric type"`  
> `fun(a::T, b::S) where {T<:A,S} = "any parametric type"`  
> `fun(b::S, a::T) where {T<:A,S} = "any parametric type"`

Then, `fun(A(A(1)), A(1))` returns an ambiguity where I expected it to return the string `"same parametric type"`.

Does someone know if this is the expected behaviour? From my (certainly limited) understanding of the multiple dispatch, I do not see why this is ambiguous… (btw I use Julia 1.4.1)

**EDIT:** it seems that

> `f1(a::A{T}, b::T) where {T} = "same parametric type"`  
> `f1(a::T, b::S) where {T<:A,S} = "any parametric type"`

does not yield methods ambiguity. However,

> `f2(a::A{T}, b::T) where {T} = "same parametric type"`  
> `f2(b::S, a::T) where {T<:A,S} = "any parametric type"`

is enough to throw the `MethodError` ambiguity. Moreover, the `Possible fix`suggested by Julia is

`Possible fix, define f2(::S, ::T) where {T<:A, S<:(A{T} where T)}`

which to me seems superfluous.

---

<div class="post-metadata">

**Author:** ![lhnguyen-vn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lhnguyen-vn/32/15449_2.png) [@lhnguyen-vn](https://discourse.julialang.org/u/lhnguyen-vn)\
**Post date:** [May 20, 2020, 2:13am UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/2 "2020-05-20T02:13:40Z")

</div>

Julia’s multiple dispatch mechanism works by selecting the most specific method given your arguments. The problem when calling `f2(A(A(1)), A(1))` is that neither methods are more specific than the other.  
`A{T}` is more specific than `S` for the first argument `A(A(1))`, but `T where T<:A` is more specific for the second argument `A(1)`, hence the `MethodError` ambiguity.

---

<div class="post-metadata">

**Author:** ![Bigorneau](https://avatars.discourse-cdn.com/v4/letter/b/4491bb/32.png) [@Bigorneau](https://discourse.julialang.org/u/Bigorneau)\
**Post date:** [May 20, 2020, 2:20am UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/3 "2020-05-20T02:20:53Z")

</div>

I completely agree about your first paragraph; hence my question!

Although, your second paragraph suggests that Julia only looks at the arguments “one at a time”; this was not my understanding… When looking at both the arguments, the choice of the method is obvious.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 20, 2020, 2:32am UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/4 "2020-05-20T02:32:31Z")

</div>

My understanding is that a method with argument type `A` is more specific than a function with argument type `B` if `A <: B`. For the two methods

```julia
f(a::A{T}, b::T) where {T} = "same parametric type"
f(b, a::A) = "any parametric type"

```

the argument types are `Tuple{A{T},T} where T` and `Tuple{Any,A}`. It is clear that

```julia
julia> (Tuple{A{T},T} where T) >: Tuple{Any,A}
false

```

because of types like `Tuple{Int,A{Float64}}` which is a subset of the latter but not of the former. Furthermore, we also have

```julia
julia> (Tuple{A{T},T} where T) <: Tuple{Any,A}
false

```

because of types like `Tuple{A{Int},Int}` which is a subset of the former but not of the latter. Hence neither method is more specific.

---

<div class="post-metadata">

**Author:** ![Bigorneau](https://avatars.discourse-cdn.com/v4/letter/b/4491bb/32.png) [@Bigorneau](https://discourse.julialang.org/u/Bigorneau)\
**Post date:** [May 20, 2020, 2:58am UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/5 "2020-05-20T02:58:01Z")

</div>

Interesting. In fact I would expect your ordering to work as well…

It just seems that I misunderstood how the multiple dispatch works.

If

```julia
h(::Type{A{T}},::Type{T}) where {T} = true
h(::Type{S},::Type{T}) where {S,T<:A} = false
julia> h(A{A{Int}},A{Int})
ERROR: MethodError: h(::Type{A{A{Int64}}}, ::Type{A{Int64}}) is ambiguous. Candidates:
  h(::Type{A{T}}, ::Type{T}) where T in Main at none:1
  h(::Type{S}, ::Type{T}) where {S, T<:A} in Main at none:1
Possible fix, define
  h(::Type{A{T}}, ::Type{T}) where T<:A

```

I agree that `(Tuple{A{T},T} where T<:A) <: Tuple{Any,A}` and `(Tuple{A{T},T} where T<:A) <: (Tuple{A{T},T} where T)` should both be true.

However, observe that for `h(A{A{Int}},A{Int})` satisfies the definition `h(::Type{A{T}},::Type{T}) where {T}` two times : the first argument matches the expected type `A{T}` **and** the parameter of the first argument `T` which is the type of the second argument also matches.

Meanwhile, our second definition of `h` is only satisfied by a match with the second argument.

As a matter of fact, the fact that the possible fix given by Julia is to define

```julia
h(::Type{A{T}}, ::Type{T}) where T<:A

```

tells me that Julia kind of already know what to do!

**EDIT:** clearly Julia has a straightforward “set understanding” of the situation and returns the error as it is only concerned with the fact that `Tuple{A{A{Int}},A{Int}}` lies in the intersection of `Tuple{Any,A}` and `Tuple{A{T},T} where T`.

---

<div class="post-metadata">

**Author:** ![lhnguyen-vn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lhnguyen-vn/32/15449_2.png) [@lhnguyen-vn](https://discourse.julialang.org/u/lhnguyen-vn)\
**Post date:** [May 20, 2020, 4:31am UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/6 "2020-05-20T04:31:45Z")

</div>

It might seem that the first definition is tighter, but the method will accept any `T` you want to throw at it. The second method, however, specifically limits the type of the second argument to only subtypes of `A`. From this perspective, it’s unclear which method is more specific: do we want to prioritize the requirement that the first argument is parametrized with the same type, or that the second argument must be subtyping `A`?  
Hence Julia suggests the fix: define a method that enforces both requirements, which will be more specific than both previously defined methods.

---

<div class="post-metadata">

**Author:** ![Bigorneau](https://avatars.discourse-cdn.com/v4/letter/b/4491bb/32.png) [@Bigorneau](https://discourse.julialang.org/u/Bigorneau)\
**Post date:** [May 20, 2020, 3:46pm UTC](https://discourse.julialang.org/t/strange-methoderror-ambiguity/39779/7 "2020-05-20T15:46:25Z")

</div>

Thanks for the discussion! I agree.

I guess it is now a point of view to add this “priority feature” and perhaps not having this flexibility is actually much better and prevent weird edge cases / forces clarity / etc…
