Make a changed copy without mutating the original.

copy-update The generated `copy` method returns a new case class instance with selected fields replaced. The original stays unchanged, which keeps state immutable.

Copy and Update

deposit
CopyUpdate.scala
Replay: real traced execution (multi-file project)
case class Account(owner: String, balance: Int)

object Main {
  def main(args: Array[String]): Unit = {
    val deposit = 50
    val base = Account("Ann", 100)
    val balance = base.balance + deposit
    val updated = base.copy(balance = balance)

    println("owner=" + updated.owner)
    println("oldBalance=" + base.balance)
    println("newBalance=" + updated.balance)
  }
}
case class Account(owner: String, balance: Int)

object Main {
  def main(args: Array[String]): Unit = {
    val deposit = 10
    val base = Account("Ann", 100)
    val balance = base.balance + deposit
    val updated = base.copy(balance = balance)

    println("owner=" + updated.owner)
    println("oldBalance=" + base.balance)
    println("newBalance=" + updated.balance)
  }
}
case class Account(owner: String, balance: Int)

object Main {
  def main(args: Array[String]): Unit = {
    val deposit = 200
    val base = Account("Ann", 100)
    val balance = base.balance + deposit
    val updated = base.copy(balance = balance)

    println("owner=" + updated.owner)
    println("oldBalance=" + base.balance)
    println("newBalance=" + updated.balance)
  }
}
  1. deposit ← 50, base ← Account(Ann,100), balance ← 150, updated ← Account(Ann,150)

    3object Main {4  def main(args: Array[String]): Unit = {5    val deposit→ 50 = 50 //@deposit=10, 2006    val base→ Account(Ann,100) = Account("Ann", 100)7    val balance→ 150 = baseAccount(Ann,100).balance + deposit508    val updated→ Account(Ann,150) = baseAccount(Ann,100).copy(balance→ 150 = balance)910    println("owner=" + updated.ownerAnn)11    println("oldBalance=" + base.balance100)12    println("newBalance=" + updated.balance150)13  }14}
    outputowner=Ann
    oldBalance=100
    newBalance=150
  1. deposit ← 10, base ← Account(Ann,100), balance ← 110, updated ← Account(Ann,110)

    3object Main {4  def main(args: Array[String]): Unit = {5    val deposit→ 10 = 106    val base→ Account(Ann,100) = Account("Ann", 100)7    val balance→ 110 = baseAccount(Ann,100).balance + deposit108    val updated→ Account(Ann,110) = baseAccount(Ann,100).copy(balance→ 110 = balance)910    println("owner=" + updated.ownerAnn)11    println("oldBalance=" + base.balance100)12    println("newBalance=" + updated.balance110)13  }14}
    outputowner=Ann
    oldBalance=100
    newBalance=110
  1. deposit ← 200, base ← Account(Ann,100), balance ← 300, updated ← Account(Ann,300)

    3object Main {4  def main(args: Array[String]): Unit = {5    val deposit→ 200 = 2006    val base→ Account(Ann,100) = Account("Ann", 100)7    val balance→ 300 = baseAccount(Ann,100).balance + deposit2008    val updated→ Account(Ann,300) = baseAccount(Ann,100).copy(balance→ 300 = balance)910    println("owner=" + updated.ownerAnn)11    println("oldBalance=" + base.balance100)12    println("newBalance=" + updated.balance300)13  }14}
    outputowner=Ann
    oldBalance=100
    newBalance=300

Follow the Copy

  1. deposit starts at 50.
  2. base is Account("Ann", 100).
  3. balance adds the deposit: 100 + 50 = 150.
  4. base.copy(balance = balance) makes updated with the new balance.
  5. The original base.balance still prints as 100. | deposit | old balance | new balance | owner | | ---: | ---: | ---: | --- | | 10 | 100 | 110 | Ann | | 50 | 100 | 150 | Ann | | 200 | 100 | 300 | Ann |

Exercise: CopyUpdate.scala

Reproduce owner=Ann, oldBalance=100, and newBalance=150, then use deposits 10 and 200 to predict newBalance=110 and newBalance=300.