Is it possible to update the documentation to specify why using parametric methods might be beneficial?

Consider the following example from the documentation

same_type(x::T, y::T) where {T} = true
same_type(x,y) = false

same_type(1, 2) # True
same_type(1, 2.0) # False

A new comer might wonder why they just can’t write it out in one function:

same_type(x,y) = isequal(typeof(x),typeof(y)) ? true : false

same_type(1, 2) # True
same_type(1, 2.0) # False

Suppose you want to limit the types to just Number as in this example:

same_type_numeric(x::T, y::T) where {T<:Number} = true
same_type_numeric(x::Number, y::Number) = false

same_type_numeric(1, 2) # True
same_type_numeric(1, 2.0) # False
same_type_numeric("foo", 2.0) MethodError

Again, you can write it out in one function:

same_type_numeric(x::Number, y::Number) = isequal(typeof(x),typeof(y)) ? true : false

As pointed out, it depends on the context. Could we come up with a more specific context to demonstrate why using parametric methods might be beneficial?

For example:

  • Come up with a function that carries out a more elaborate task than just returning true or false. Demonstrate why using type annotations alone might not be so good, and then show how a parametric function would be better.

  • Consider that the documentation uses multiple dispatch, we could again demonstrate a better example of multiple dispatch with parametric methods and the benefits of doing it.

  • Elaborate on why sometimes type annotations alone might be enough. I’m not saying parametric methods will solve every problem, or that every method that uses type annotations should be converted to parametric methods. Both obviously exist to solve different problems, maybe we can explore briefly why we might favour type annotations over parametric functions.

The simple ternary/if expression trick works if there’s just two arguments, but if there are more it quickly gets mor complicated and harder to reason about. Additionally, the explicit if check relies on constant propagation to eliminate the branch, which is not always guaranteed to happen, whereas the explicitly dispatched version doesn’t have this problem.

Also, being clear in the method signature about the type restrictions placed on each argument makes it much easier to reason about how those variables could be used, instead of having to read & understand the complete function before knowing what could happen. It’s one part of isolating behavior to the relevant methods, instead of having a single big function that does it all.

If we’d update the documentation, I think adding something inspired by the above would be a nice addition (though I have to admit, to me it follows from what’s already in there).

1 Like