Kotlin supports a lot of ways to write immutable data structures and will even provide real immutable collections in the future.
What I’m missing is a good way to “update” an immutable data class, like you can do in, for example, F# which has it as a keyword.
The idea
Lets say I have this data class:
data class Person(val name: String, val age: Int)
at the moment I have to write a boilerplate function for every data class to get the “wither” that I want:
fun Person.with(name: String? = null, age: Int? = null) = Person(name ?: this.name, age ?: this.age)
which allows me to use it like this:
fun main(args: Array<String>) {
val tom = Person("Tom", 15)
val max = tom.with(name = "Max")
println(tom)
println(max)
}
Output:
Person(name=Tom, age=15)
Person(name=Max, age=15)
Since it really is just a boilerplate function (it takes all properties as nullable optional arguments) it could be something compiler generated.
Problems
Having multiple constructors might be a problem, which I haven’t stumpled upon yet since I always write the function for the constructor with the most arguments.
However, generating a wither for every constructor works, as it is not ambigious:
data class Person(val name: String, val age: Int) {
constructor(name: String) : this(name, 0)
constructor(age: Int) : this("", age)
}
fun Person.with(name: String? = null, age: Int? = null) = Person(name ?: this.name, age ?: this.age)
fun Person.with(name: String? = null) = Person(name ?: this.name)
fun Person.with(age: Int? = null) = Person(age ?: this.age)
Alternative Syntax
An alternative could be to create a wither for every property:
fun main(args: Array<String>) {
val tom = Person("Tom", 15)
val max = tom.withName(name = "Max")
println(tom)
println(max)
}
data class Person(val name: String, val age: Int)
fun Person.withName(name: String) = Person(name, this.age)
fun Person.withAge(age: Int) = Person(this.name, age)
Output:
Person(name=Tom, age=15)
Person(name=Max, age=15)