Background: I'm working on converting this F# discriminated union to Elixir:
type Suit =
| Diamonds
| Clubs
| Hearts
| Spades
I know there are a few different ways to do that, and that's not my question.
The following need to be true:
Diamonds == Diamonds
Diamonds < Hearts
Spades > Hearts
I was surprised to find that Elixir doesn't have a comparable protocol similar to Haskell's Ord typeclass and this implementation on GitHub (with very few stars!)
Is there a well-accepted or idiomatic way to make custom types comparable?
The idiomatic way to do this is to simply provide equal?/2 and/or compare/2 in the module that defines the custom type. This can be seen frequently in the core libraries and robust third-party libraries.
For example, Date.compare/2 has the following specification
compare(Calendar.date(), Calendar.date()) :: :lt | :eq | :gt
Starting with v1.10.0, Elixir provides handy sorting with Enum.sort/2 for structs implementing compare/2:
defmodule User do
defstruct [:name]
def compare(%User{name: n1}, %User{name: n2}) when n1 < n2,
do: :lt
def compare(%User{name: n1}, %User{name: n2}) when n1 > n2,
do: :gt
def compare(%User{}, %User{}), do: :eq
end
users = [
%User{name: "john"},
%User{name: "joe"},
%User{name: "jane"}
]
Enum.sort(users, {:asc, User})
#⇒ [%User{name: "jane"},
# %User{name: "joe"},
# %User{name: "john"}]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With