I have taken a look at Enum.sort and it is great to have the option to give the function a module to use the module.compare/2 function. But, wouldn’t it be nice if the module implemented a Comparable protocol?
In this case, Comparable would be a Protocol with just compare/2 as the only function.
As for your specific suggestion: An immediate problem is that we might want to compare two different datatypes with one-another. Now the question becomes: which protocol implementation to call?
Passing a module (and using compare as a “behaviour” function) is more flexible and handles these kinds of situations without problem.
There’s a certain amount of overhead for protocol dispatch. I haven’t measured how much, but there’s certainly more work for the compiler.
Another reason (I suspect) is historical: a lot of data types had a compare function even before sort supported this option, so most of the protocol implementations would be trivial:
defimpl Comparable, for: DateTime do
def compare(d1, d2), do: DateTime.compare(d1, d2)
end
But the subtlest reason is because protocol dispatch isn’t symmetric in its arguments if they aren’t the same type. For instance, if you have the following:
defimpl Comparable, for: A do
def compare(a1, a2), do: ...
end
defimpl Comparable, for: B do
def compare(b1, b2), do: ...
end
Then sorting a list of mixed A and B structs will dispatch calls like Comparable.compare(a, b) and Comparable.compare(b, a) - which lead to DIFFERENT functions based on the first argument.