25
votes

Case classes in Scala are standard classes enhanced with pattern-matching, equals, ... (or am I wrong?). Moreover they require no "new" keyword for their instanciation. It seems to me that they are simpler to define than regular classes (or am I again wrong?).

There are lots of web pages telling where they should be used (mostly about pattern matchin). But where should they be avoided ? Why don't we use them everywhere ?

4

4 Answers

20
votes

There are many places where case classes are not adequate:

  • When one wishes to hide the data structure.
  • As part of a type hierarchy of more than two or three levels.
  • When the constructor requires special considerations.
  • When the extractor requires special considerations.
  • When equality and hash code requires special considerations.

Sometimes these requirements show up late in the design, and requires one to convert a case class into a normal class. Since the benefits of a case class really aren't all that great -- aside from the few special cases they were specially made for -- my own recommendation is not to make anything a case class unless there's a clear use for it.

Or, in other words, do not overdesign.

16
votes

Inheriting from case classes is problematic. Suppose you have code like so:

case class Person(name: String) { }

case class Homeowner(address: String,override val name: String)
  extends Person(name) { }

scala> Person("John") == Homeowner("1 Main St","John")
res0:  Boolean = true

scala> Homeowner("1 Main St","John") == Person("John")
res1: Boolean = false

Perhaps this is what you want, but usually you want a==b if and only if b==a. Unfortunately, the compiler can't sensibly fix this for you automatically.

This gets even worse because the hashCode of Person("John") is not the same as the hashCode of Homeowner("1 Main St","John"), so now equals acts weird and hashCode acts weird.

As long as you know what to expect, inheriting from case classes can give comprehensible results, but it has come to be viewed as bad form (and thus has been deprecated in 2.8).

1
votes

One downside that is mentioned in Programming in Scala is that due to the things automatically generated for case classes the objects get larger than for normal classes, so if memory efficiency is important, you might want to use regular classes.

0
votes

It can be tempting to use case classes because you want free toString/equals/hashCode. This can cause problems, so avoid doing that.

I do wish there were an annotation that let you get those handy things without making a case class, but maybe that's harder than it sounds.