Alex Rivera | Logout

Choosing between a class and a record

Asked 2011-11-12T18:56:57.427
35

Basic question: what design principles should one follow when choosing between using a class or using a record (with polymorphic fields) ?

First, we know that classes and records are essentially equivalent (since in Core, classes get desugared to dictionaries, which are just records). Nevertheless, there are differences: classes are passed implicitly, records must be explicit.

Looking a little deeper, classes are really useful when:

  1. we have many different representations of 'the same thing', and
  2. in actual usage, which representation is used can be inferred.

Classes are awkward when we have (up to parametric polymorphism) only one representation of our data, but we have multiple instances. This leads to the syntactic noise of having to use newtype to add extra tags (which exist only in our code, as we know such tags get erased at run time) if we don't want to turn on all sorts of troublesome extensions (i.e. overlapping and/or undecidable instances).

Of course, things get muddier: what if I want to have constraints on my types? Let's pick a real example:

class (Bounded i, Enum i) => Partition a i where
    index :: a -> i

I could just as easily have done

data Partition a i = Partition { index :: a -> i}

But now I've lost my constraints, and I will have to add them to specific functions instead.

Are there design guidelines that would help me out?

Edit
Report

1 Answer

1

Type-classes can sometimes provide additional type-safety (An example would be Ord with Data.Map.union). If you have similar circumstances where choosing type-classes may help your type-safety - then use type-classes.

I'll present a different example where I think type-classes would not provide additional safety:

class Drawing a where
    drawAsHtml :: a -> Html
    drawOpenGL :: a -> IO ()

exampleFunctionA :: Drawing a => a -> a -> Something
exampleFunctionB :: (Drawing a, Drawing b) => a -> b -> Something

There is nothing exampleFunctionA could do and exampleFunctionB could not do (I find it hard to explain why, insights are welcome).

In this case I see no benefit of using a type-class.

(Edited following feedback from Jacques and question from missingo)

answered 2011-11-12T22:18:45.423

Your Answer