Scala Language Case Classes Single Element Case Classes for Type Safety


In order to achieve type safety sometimes we want to avoid the use of primitive types on our domain. For instance, imagine a Person with a name. Typically, we would encode the name as a String. However, it would not be hard to mix a String representing a Person's name with a String representing an error message:

def logError(message: ErrorMessage): Unit = ???
case class Person(name: String)
val maybeName: Either[String, String] = ??? // Left is error, Right is name
maybeName.foreach(logError) // But that won't stop me from logging the name as an error!

To avoid such pitfalls you can encode the data like this:

case class PersonName(value: String)
case class ErrorMessage(value: String)
case class Person(name: PersonName)

and now our code will not compile if we mix PersonName with ErrorMessage, or even an ordinary String.

val maybeName: Either[ErrorMessage, PersonName] = ???
maybeName.foreach(reportError) // ERROR: tried to pass PersonName; ErrorMessage expected
maybeName.swap.foreach(reportError) // OK

But this incurs a small runtime overhead as we now have to box/unbox Strings to/from their PersonName containers. In order to avoid this, one can make PersonName and ErrorMessage value classes:

case class PersonName(val value: String) extends AnyVal
case class ErrorMessage(val value: String) extends AnyVal