In Kotlin, shallow copy creates a new object, but nested objects (such as collection elements or reference fields) are not copied, but reference the same objects as the original instance. Deep copy means recursively copying all nested objects (the object graph) so that the original and the copy are completely independent.
There is no universal means for deep copying in the Kotlin standard library, and it needs to be implemented manually, especially for complex structures or graphs with cycles.
data class Person(val name: String, val addresses: List<String>) val original = Person("Anna", listOf("Moscow", "London")) val shallow = original.copy() println(original.addresses === shallow.addresses) // true, the same reference
data class Person(val name: String, val addresses: List<String>) { fun deepCopy(): Person = Person(name, addresses.toList()) } val deep = original.deepCopy() printfn(original.addresses === deep.addresses) // false, new copy of the list
If
.copy()is used for a data class with nested collections, will the collections be copied? Why?
No, copy() creates a shallow copy. Nested collections and objects will remain references to the same objects. Any changes to these objects will be visible in both the original and the copy, which can lead to bugs.
data class Box(val items: MutableList<String>) val box1 = Box(mutableListOf("A")) val box2 = box1.copy() box2.items.add("B") printfn(box1.items) // [A, B] — original was modified!
Story
In the project, we saved the object's state through a regular
.copy()of a data class, believing that we get a "snapshot". When returning to the old state, it turned out that the nested list (mutableList) was changed in all copies due to shallow copying.
Story
In the document system, we copied entities through serialization/deserialization using Gson, expecting deep copying, but nullable fields and dates were serialized incorrectly — as a result, incorrect values and business logic errors appeared.
Story
When migrating state in a Redux-like store for Android development, we started using
copy()for state trees, expecting complete independence of copies. As a result, one branch of the store could mutate the state of another due to references to the same internal mutable collections.