Typeclasses vs Modules

31 points by abhin4v


bos

One of the pervasive problems with type classes is that they lock you into one global meaning and implementation for a name.

If absolutely everyone agrees that this one meaning always makes sense, that’s fine, but if your understanding evolves, you’ve now got a major problem because any change can break unexpected parts of your ecosystem.

We ran into just this with the Hashable type class in Haskell many years ago. The standard implementation of Hashable for integers is to just convert to an Int, so basically the identity function.

For some uses, this is fine, but for a majority of hashing purposes, you want to mix the bits, and because fast hashing with good mixing properties has been an active area of research for many years, you can very reasonably expect a large program to have different hashing needs in different places, depending either on use case or the age of a section of code.

This is all pretty easy to achieve with an ML-style module system, but type classes are literally the wrong tool for this job due to their virality and rigidity. Unfortunately I didn’t come to this conclusion until way too late, and the Backpack module system in Haskell didn’t even exist at the time we were struggling with this.

The deeper problem with type classes is they make a policy choice look like an intrinsic property of a type.

An integer doesn’t have one natural hash. It has a representation, and you choose a hashing strategy for a particular consumer: bucket selection, fingerprints, composite keys, partitioning, and so on. Those consumers can need different properties. A global Hashable Int instance erases that distinction.

If I was redoing Hashable using Haskell’s Backpack module system, it would look quite different. However, Backpack is also kind of a pain in the ass to work with, whereas type classes also have this seductive property of being very easy and notationally lightweight.

Modules in Haskell are a plate of steamed broccoli, while type classes are a quart of ice cream. Ocaml has much nicer ergonomics for its module system, but they’re somewhat uglier to read than type classes.