Controlled value semantics in Scala
I recently discovered
AutoValue for
Java, which uses annotation-driven code generation to ease the writing of
classes with value semantics (that is to say, classes without object identity).
In Scala, one can accomplish a similar result with case classes, but these also
come bundled with a selection of other features – copy
methods and
pattern-matching support, for instance. In the case that one only seeks
immutable value semantics, there is a need to hide some of this generated
behaviour. The trick I employed was to use a sealed trait, viz.:
sealed trait Account {
def id: AccountId
def email: Email
}
object Account {
case class Account_ private[Account]
(val id: AccountId, val email: Email) extends Account
def create(id: AccountId, email: Email): Account =
Account_(id, email)
}
The private case class buys us appropriate equals
and hashCode
implementations, but the trait hides the unwanted copy
and apply
methods
from the consumer. The trait’s companion object provides the create
factory
method, meaning that the trait can in effect be treated as a concrete type.
Note: the toString
method will be slightly off (mentioning the
private Account_
type as opposed to the public Account
trait), but this is
of no consequence in my case. Your mileage may vary.