Understanding the diagonal rule

As we learned earlier, it is a nice feature to be able to match type variables and keep them consistent across method arguments. In practice, there are situations where we want to be even more specific when determining the right type for each type variable.

Consider this function:

diagonal(x::T, y::T) where {T <: Number} = T

The diagonal function takes two arguments with the same type, where the type T must be a subtype of Number. The type variable T is simply returned to the caller.

When T is concrete, it is easy to reason that the types are consistent. For example, we can pass a pair of Int64 values or a pair of Float64 values to the function and expect to see the respective concrete type returned:

Intuitively, we also expect this to fail when the types are not consistent:

While it seems to work intuitively, we could have argued that the type variable T is an abstract type, such as Real. Since the value of 1 is Int64 and Int64 is a subtype of Real, and the value of 2.0 is Float64 and Float64 is a subtype of Real, shouldn't the method still get dispatched anyway? To make this point more clear, we can even annotate the argument as such when calling the function:

It turns out that Julia is designed to give us more intuitive behavior. It is also the very reason why the diagonal rule was introduced. The diagonal rule says that when a type variable occurs more than once in the covariant position (that is, the method arguments), then the type variable will be restricted to match with concrete types only. 

In this case, the type variable T is considered a diagonal variable, so T must be a concrete type.

There is an exception to the diagonal rule, though. We will discuss this next.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.85