Replace Mutator Method with Deep Copy


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.


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.title}")
// employee0: George Michael, Employee

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


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.


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}")


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