I’ve encountered what appears to be an inconsistency with method specificity. However, since it’s considerably more likely that I’m just confused, I thought I’d ask here before creating an issue.
My basic expectation is that in the following simple example the method that uses a type parameter constrains the two arguments to be of the same type, and so it is more specific:
julia> foo(x::Integer, y::Integer) = "generic"
julia> foo(x::T, y::T) where {T <: Integer} = "specific"
julia> foo(1, 2)
"specific"
julia> foo(Int8(1), 2)
"generic"
That indeed works as expected. If I introduce a parametric type:
julia> struct Foo{T <: Integer}
x::T
y::T
end
julia> methods(Foo)
# 1 method for type constructor:
[1] Foo(x::T, y::T) where T<:Integer in Main
julia> Foo(x::Integer, y::Integer) = "generic"
julia> Foo(1, 2)
Foo{Int64}(1, 2)
julia> Foo(Int8(1), 2)
"generic"
That also follows my expectations. If I introduce one more parametric type:
julia> struct Bar{T}
x::Foo{T}
y::Foo{T}
end
julia> methods(Bar)
# 1 method for type constructor:
[1] Bar(x::Foo{T}, y::Foo{T}) where T in Main
julia> Bar(x::Foo, y::Foo) = "generic"
julia> Bar(Foo(1, 2), Foo(1, 2))
"generic"
julia> Bar(Foo(Int8(1), Int8(2)), Foo(1, 2))
"generic"
Why didn’t the first call to Bar
dispatch to the constructor provided by Julia?