Enum.sort(enumerable, module) - why not Enum.sort(enumerable, comparable)

Hello,

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.

What do you think?

Hi @marcus there have been some proposals for a comparable protocol before on the mailing list: https://groups.google.com/forum/#!searchin/elixir-lang-core/comparable|sort:date/elixir-lang-core/eE_mMWKdVYY/A5n0vuPpAQAJ

2 Likes

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.

3 Likes

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.

2 Likes