Kotlin data class copy method not deep copying all members

The copy method of Kotlin is not supposed to be a deep copy at all. As explained in the reference doc (https://kotlinlang.org/docs/reference/data-classes.html), for a class such as:

data class User(val name: String = "", val age: Int = 0)

the copy implementation would be:

fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

So as you can see, it's a shallow copy. The implementations of copy in your specific cases would be:

fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list) = Foo(a, bar, list)

fun copy(x: Int = this.x) = Bar(x)

There is a way to make a deep copy of an object in Kotlin (and Java): serialize it to memory and then deserialize it back to a new object. This will only work if all the data contained in the object are either primitives or implement the Serializable interface

Here is an explanation with sample Kotlin code https://rosettacode.org/wiki/Deepcopy#Kotlin

import java.io.Serializable
import java.io.ByteArrayOutputStream
import java.io.ByteArrayInputStream
import java.io.ObjectOutputStream
import java.io.ObjectInputStream

fun <T : Serializable> deepCopy(obj: T?): T? {
    if (obj == null) return null
    val baos = ByteArrayOutputStream()
    val oos  = ObjectOutputStream(baos)
    oos.writeObject(obj)
    oos.close()
    val bais = ByteArrayInputStream(baos.toByteArray())
    val ois  = ObjectInputStream(bais)
    @Suppress("unchecked_cast")
    return ois.readObject() as T
} 

Note: This solution should also be applicable in Android using the Parcelable interface instead of the Serializable. Parcelable is more efficient.


As @Ekeko said, the default copy() function implemented for data class is a shallow copy which looks like this:

fun copy(a: Int = this.a, bar: Bar = this.bar, list: MutableList<Int> = this.list)

To perform a deep copy, you have to override the copy() function.

fun copy(a: Int = this.a, bar: Bar = this.bar.copy(), list: MutableList<Int> = this.list.toList()) = Foo(a, bar, list)