Scala – How to override apply in a case class companion

case-classpattern matchingscala

So here's the situation. I want to define a case class like so:

case class A(val s: String)

and I want to define an object to ensure that when I create instances of the class, the value for 's' is always uppercase, like so:

object A {
  def apply(s: String) = new A(s.toUpperCase)
}

However, this doesn't work since Scala is complaining that the apply(s: String) method is defined twice. I understand that the case class syntax will automatically define it for me, but isn't there another way I can achieve this? I'd like to stick with the case class since I want to use it for pattern matching.

Best Answer

The reason for the conflict is that the case class provides the exact same apply() method (same signature).

First of all I would like to suggest you use require:

case class A(s: String) {
  require(! s.toCharArray.exists( _.isLower ), "Bad string: "+ s)
}

This will throw an Exception if the user tries to create an instance where s includes lower case chars. This is a good use of case classes, since what you put into the constructor also is what you get out when you use pattern matching (match).

If this is not what you want, then I would make the constructor private and force the users to only use the apply method:

class A private (val s: String) {
}

object A {
  def apply(s: String): A = new A(s.toUpperCase)
}

As you see, A is no longer a case class. I am not sure if case classes with immutable fields are meant for modification of the incoming values, since the name "case class" implies it should be possible to extract the (unmodified) constructor arguments using match.