Search code examples
scalaimmutabilitycase-classconstructor-overloading

Case class immutable still able to change the parameter values


I reviewed some code from a colleague and I came across a case class which is by default immutable.

the below case class can be changed so my question is how is this possible since case classes are immutable but in this construct i can change the case class parameters?

case class RegisterCustomerRequest(`first-name`: String,
                                   `last-name`: String,
                                   `house-details`: String,
                                   street: String,
                                   zipcode: String,
                                   city: String

    extends WcRequestData {

    def this(cardHolderData: CardHolderData,
           registrationCode: RegistrationCode,
           customerNumber: Long,
           cardDesignImageId: String) =
    this(`first-name` = cardHolderData.firstname,
         `last-name` = cardHolderData.lastname,
          street = cardHolderData.streetAndNumber,
          zipcode = cardHolderData.zipCode,
          city = cardHolderData.city,


       #   `house-details` = 
          s"${if (cardHolderData.employerName.contains("&")) 
          cardHolderData.employerName.replace("&" , " & ") else " / 
           "}${cardHolderData.employerName} ")#
    }

why can I define a def this method which can change the values of parameters. What is this construct good for is this good coding style?


Solution

  • The case class RegisterCustomerRequest is still immutable however it has an auxiliary constructor def this which allows it to be constructed in a different way. For example, given

    case class User(name: String)
    
    case class Foo(name: String) {
      def this(user: User) {
        this(name = user.name)
      }
    }
    

    we can construct Foo like so

    Foo("picard")
    

    or using the auxiliary constructor

    new Foo(User("picard"))
    

    In both cases the result is an immutable object. To confirm immutability try reassigning name after construction

    (new Foo(User("picard"))).name = "worf" // Error: reassignment to val 
    

    As suggested by som-snytt, we can define apply method on companion object instead of auxiliary constructor like so

    object Foo {
      def apply(user: User): Foo = Foo(user.name)
    }
    

    which enables the following construction

    Foo(User("picard"))