Yes, your example would throw a method ambiguity error. But I think that when interfaces and generic functions are well designed, those sorts of ambiguities shouldnât be too common. Letâs look at a more extended example.
Suppose PkgA defines the following abstract types:
module PkgA
abstract type A end
abstract type B <: A end
abstract type C <: A end
export A, B, C
end
Now suppose PkgB defines the function foo. One design principle that I promote for generic functions is that there should only be one docstring for each arity of a generic function. In other words, each arity of a function has exactly one defined behavior. So PkgB might define foo as follows:
module PkgB
"""
    foo(x::A)
Take an `A` and do something with it.
"""
foo(x::A) = # ...
foo(x::B) = # ...
foo(x::C) = # ...
export foo
end
The foo(x::B) and foo(x::C) methods are specializations of foo that still have the same generic behavior as foo(x::A).
Now suppose PkgC defines a concrete type D. First of all, in the presence of multiple inheritance, I think concrete types are more likely to inherit from abstract types that are not directly related to each other, similar to this made up example:
struct Foo <: Graph, Eq, Serializable end
So, the type D in PkgC is more likely to look like this,
module PkgC
using PkgA
struct D <: B, Z end
end
than to look like this,
module PkgC
using PkgA
struct D <: B, C end
end
And thus, for the type struct D <: B, Z end, there wonât be any method ambiguity when you call foo(D()).
If the type D is defined as struct D <: B, C end, then yes, foo(D()) would result in an ambiguity error. This could indicate that objects of type Intersection{B, C} are common, and it would make sense for the developer of PkgB to add a method foo(x::Intersection{B, C}). Alternatively, it might make sense for the developer of PkgC to add a method foo(x::D).
This is similar to the current situation with method ambiguities. If a package author defines the following two methods for bar, then they should really also define a third method to resolve the method ambiguity:
bar(x::Integer, y::Int) = 1
bar(x::Int, y::Integer) = 2
At any rate, this is all speculation at this point. We wonât really know how severe of a problem method ambiguities will be until we have a working prototype to experiment with in the ecosystem.