(==) is overrated

06 September 2024

When I first learned Haskell, one of the first habits I picked up was adding deriving (Show, Eq) to every type definition I write. Eventually I added Generic to this list, but if you looked at my code now, you wouldn’t find Eq in there anymore.

To motivate this I’m going to start off with a pretty strong claim: deep equality checking is almost never actually what you want.

If you ever talked to someone working with dependent types, they probably talked your ear off about equality and they probably had a point, but that’s not the kind of equality we’re talking about here. (==) is not a property you can use in proofs or anything like that, it’s just a function that lets you check at runtime if two things are equal. Now I want you to ask yourself: how often do you actually need this operation on interesting data types?

Integers? Sure. Strings? Yes, although if you’re doing it a lot you should probably intern your strings anyway. But beyond that? There’s really not a lot.

On the flip side, deep equality (the kind deriving Eq generates) is linear in the size of your data and a great way to kill your performance. I work on compilers a lot and I deliberately make sure to never derive Eq on syntax trees because checking those for equality is probably the easiest way to create quadratic runtime behavior.