Right now I have classes like:
abstract class Record {
// Required fields
val productCode:Option[String]
val price:Option[Double]
// Optional fields
val notes:Option[String] = None
val used:Option[Boolean] = Option(false)
}
Then create them:
val r = new Record {
override val productCode = Option("abc")
override val price = Option(32.12)
}
A few things to note:
- I use Option for the un-optional fields so that a. I don't have to remember which fields are optional b. I can change which fields are optional without changing my interface
- The Option stuff adds a lot of noise. I'd love for that not to be there, but I also don't want to use nulls. This is particularly true when taking into account all the calls to getOrElse when I'm using the structure. (I bet there's a clever way for the language to declaratively autobox these.)
This makes mass assignment (which I'm doing because I have an array of fields) difficult if a subclass mixes new fields in, e.g.:
override val List(productCode, price, discount) = fields // fields is a List
will not compile because discount
is not defined in the superclass and therefor not an override. I'm not sure if there is a way to do this.
My main question is:
- Is there a better overall way to manage immutable data structures?
- Is there a straightforward way to copy a record and change just one value without writing boilerplate code?
e.g. (pseudocode}:
val r2 = r.clone { override val used = true }
I have heard 2.8 introduces something like this for case classes, however in a language that encourages immutable data structures, I'd be surprised to find out this is not easier before 2.8. I'm still in 2.7.