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.