What is the triangle in "triangular dispatch"?

More than 5 year ago Tim Holey wished he could write

colorspace{C<:ColorValue,A<:AbstractArray{C}}(img::A) = string(C)

He called such a feature “triangular dispatch (left-to-right template parameter chaining)”.

Today Julia does support such “triangular” dispatch and Tim’s example can be written as

colorspace(img::A) where A<:AbstractArray{C} where C<:ColorValue = string(C)

I understand the “left-to-right template parameter chaining” part, but what makes this kind of dispatch triangular? What are the vertices of that triangle?


The ability to define a function g{T, S<:T}(::Vector{T}, ::S) has been referred to as “triangular dispatch” as an analogy to diagonal dispatch: f{T}(::Vector{T}, ::T) . (Imagine a table with a type hierarchy labelling the rows and columns, arranged such that the super types are to the top and left. The rows represent the element type of the first argument, and the columns the type of the second. Diagonal dispatch will only match the cells along the diagonal of the table, whereas triangular dispatch matches the diagonal and everything below it, forming a triangle.)


Edit: the following is wrong. It is backwards. See the correct version below this entry.

@Gnimuc, I interpret that to mean
R <: S <: T


          | T | S | R 
Vector{T} | X |   |
Vector{S} | X | X |
Vector{R} | X | X | X


          | T | S | R 
Vector{T} | X |   |
Vector{S} |   | X |
Vector{R} |   |   | X

Where X marks the combination that will cause the function g{T, R<:T}(::Vector{T}, ::R) to be dispatched.



It should be:

Vector{T} :white_check_mark: :white_check_mark:
Vector{S} x :white_check_mark:
julia> g(t::Vector{T}, s::S) where {T, S<:T} = "dispatch!"

julia> g(Integer[1], Integer(1))  # Vector{T} T

julia> g(Integer[1], Unsigned(1))  # Vector{T} S

julia> g(Unsigned[1], Integer(1))  # Vector{S} T
ERROR: MethodError: no method matching g(::Array{Unsigned,1}, ::Int64)

julia> g(Unsigned[1], Unsigned(1))  # Vector{S} S