Type stability with variable arguments

Ordering for tuples is already lexicographic as noted by @tomerarnon, so you can just map into a tuple:

lexicographic(x...) = i -> getindex.(x, i)

and sort(..., by=lexicographic(args...)).

In general, it is instructive to see how Base implements functions acting on variable-length arguments or variable-length tuples in a type-stable way. The key thing is that, because the compiler knows the length of a tuple, if you write things in the correct way then it can completely unroll loops as if you had written it out by hand.

For example, here is how isless is implemented for tuples: base/tuple.jl:isless. Note that it is recursive, but the compiler can “unroll” the recursion completely (if it is not too deep). map is implemented similarly, and also broadcasting on tuples as exploited above in the getindex.(...) call. Another useful pattern is to use the ntuple function with a Val{N} argument where N comes from a type parameter (e.g. a Vararg parameter for variable arguments), in which case the compiler can completely unroll the loop; a simple example of this can be found in the size(a::Array) function and much more extensive use can be found in the multidimensional reverse! implementation.

3 Likes