Replace Mutator Method with Deep Copy

Summary

You have a data structure with internal state that can be mutated in place by a method call.

Make the internal state immutable, and convert the mutator into a method that makes a deep copy of the data structure, with the corresponding mutation applied.

Mutable mutability

class MutableEmployee(var name: String, var title: String) {
  def setName(_name: String): Unit = {
    name = _name
  }
  def setTitle(_title: String): Unit = {
    title = _title
  }
}

Immutable mutability

class ImmutableEmployee(name: String, title: String) {
  def setName(_name: String): ImmutableEmployee =
    new ImmutableEmployee(_name, title)
  def setTitle(_title: String): ImmutableEmployee =
    new ImmutableEmployee(name, _title)
}

This is a functional take on the builder pattern.

Motivation

Mutable variables tend to preclude referential transparency, and can lead to all kind of bugs related to timing, threading, parallelism, lack of idempotency, evaluation order, lack of equational reasoning, etc.

val employee0 = new MEmployee("George Michael", "Employee")
println(s"employee0: ${employee0.name}, ${employee0.title}")
// employee0: George Michael, Employee

employee0.setTitle("Mr. Manager")
println(s"employee0: ${employee0.name}, ${employee0.title}")
// employee0: George Michael, Mr. Manager

Mechanics

Make internal state final. In Scala, this means simply replacing var with val.

Make mutator methods, which probably have no useful return information, return the type of the data structure.

Change the implementations of mutator methods to construct new instances of the data structure, propagating the existing state plus the change(s) implied by the mutator.

Example

In Scala, we get this pattern for free when we use case classes:

case class CCEmployee(name: String, title: String)

val employee1 = CCEmployee("George Michael", "Employee")
val employee2 = employee1.copy(title = "Mr. Manager")

println(s"employee1: ${employee1}")
println(s"employee2: ${employee2}")

Demo

employee1: CCEmployee(George Michael,Employee)
employee2: CCEmployee(George Michael,Mr. Manager)