Both of the methods you mentioned refer to functional and OO paradigms, respectively. If you prefer functional decomposition with an abstract data type, which is represented by case classes in Scala, then select the copy method. Using mutators is not good practice in my version because it will bring you back to Java / C # / C ++.
On the other hand, creating a case class ADT, for example
case class Person(name: String, age: String)
more consise then:
class Person(_name: String, _age: String) { var name = _name var age = _a def changeName(newName: String): Unit = { name = newName } // ... and so on }
(not the best imperative code, may be shorter, but clear).
Because of this, there is another way using mutators, just to return a new object for each call:
class Person(val name: String, val age: String) { def changeName(newName: String): Unit = new Person(newName, age) // ... and so on }
But still class class is more consensus class.
And if you go further to parallel / parallel programming, you will see that a functional concept with an immutable value is much better, and then tring to guess what state your object is in.
Update
Thanks senia , forgot to mention two things.
The lenses
At the most basic level, lenses are a kind of getter and setter for immutable data and look like this:
case class Lens[A,B](get: A => B, set: (A,B) => A) { def apply(a: A) = get(a) // ... }
That's all. A lens is an object that contains two functions: get and set. get takes A and returns B. set takes A and B and returns a new A. It is easy to see that type B is the value contained in A. When we pass an instance to get, we return that value. When we pass A and B for installation, we update the value of B in and return a new A reflecting the change. For convenience, get is applied with an alias. There is a good intro for the Case Scalaz Lens class
Posts
Because of this, it comes from a shapeless library and is called Records. Implementation of extensible records modeled as HLists associations. Keys are encoded using singleton types and fully determine the types of their corresponding values ββ(ex from github):
object author extends Field[String] object title extends Field[String] object price extends Field[Double] object inPrint extends Field[Boolean] val book = (author -> "Benjamin Pierce") :: (title -> "Types and Programming Languages") :: (price -> 44.11) :: HNil // Read price field val currentPrice = book.get(price) // Inferred type is Double currentPrice == 44.11 // Update price field, relying on static type of currentPrice val updated = book + (price -> (currentPrice+2.0)) // Add a new field val extended = updated + (inPrint -> true)