Method dispatch for tuples

I have the following definitions:

f(x::Tuple{Any, Any}) = "Tuple{Any, Any}"
f(x::NTuple{N}) where N = "NTuple{N}"

When I write f((1,2)) the call satisfies both definitions. On Julia 0.6 the second definition is called but I do not understand why. Is this a bug or there is some explanation for this behavior?

I would assume that MethodError should be thrown as this call is ambiguous because:

julia> typeof((1,2)) <: Tuple{Any, Any}
true

julia> typeof((1,2)) <: NTuple{N} where N
true

but

julia> Tuple{Any, Any} <: NTuple{N} where N
false

julia> (NTuple{N} where N) <: Tuple{Any, Any}
false

NTuple requires that all the inputs have the same type, so

julia> typeof((1,2)) <: NTuple{N} where N
true

julia> typeof((1,2.0)) <: NTuple{N} where N
false

Hence it is deemed “more specific,” as the lingo goes, and hence gets priority.

Of course this can be debated: why should the element type receive priority over the length? If you need to have manual control over this, you can always define a method for ::NTuple{2} and have it do whichever one you want.

1 Like

Thank you. Now I understand that it is governed by jl_type_morespecific.

As a side observation: for Array dimension gets the priority over element type as Array{T, 1} where T is more specific than Array{Int, N} where N (so I would say it is the other way around than in Tuple although there is no one to one correspondence between those cases).

2 Likes

That seems like a reasonable question. Relatedly, I filed an issue so that we don’t forget to document these rules someday.

2 Likes