Part of what the Scala compiler does (except in the case of an abstract case class
) with a case class
is that it generates a companion object for the class with an apply
method with the same arguments as the case class
's constructor and the case class
as a result type.
When you write val person1 = Person("Posa", 30)
, that is exactly the same as writing
val person1 = Person.apply("Posa", 30)
The automatically generated apply
method is effectively:
object Person {
def apply(name: String, age: Int): Person =
new Person(name, age)
}
Thus Person("Posa", 30)
and new Person("Posa", 30)
are the same thing.
For an abstract case class
, the compiler will not generate an apply
method in the companion object and will not generate a copy
method in the case class, thus requiring an explicit new
to construct an instance of a case class
. This is not uncommonly used in an implementation pattern to ensure that:
- only instances of a case class which satisfy domain constraints can be constructed
- attempts to construct using
apply
will not throw an exception
For example, if we wanted to enforce that Person
s must have a non-empty name and a non-negative age, we could
sealed abstract case class Person private[Person](name: String, age: Int) {
def copy(name: String = name, age: Int = age): Option[Person] =
Person(name, age)
}
object Person {
def apply(name: String, age: Int): Option[Person] =
if (name.nonEmpty && age >= 0) Some(unsafeApply(name, age))
else None
private[Person] def unsafeApply(name: String, age: Int) =
new Person(name, age) {}
}
In this, we've effectively renamed the compiler-generated apply
to unsafeApply
and made it private to the Person
class and companion object (where we presumably can know that we're not violating a domain constraint, e.g. we could have a method in Person
def afterNextBirthday: Person = Person.unsafeApply(name, age + 1)
(since we're not changing the already validated name, and if we had a valid age (ignoring overflow...), adding 1 will not invalidate the age)). Our apply
method now expresses that not all combinations of name
and age
are valid.