``` abstract class T1 { var x = 5 }...
# getting-started
p
Copy code
abstract class T1 {
        var x = 5
    }

    data class T2( 
        val y: Int
    ) : T1()

    @Test
    fun test() {
        val a = T2(y=10)
        a.x = 100
        val b = a.copy(y = 99)
        println(b.x) // 5 //  why x is not copied?
    }
h
copy creates a new object by calling the constructor of T2, but x isn’t part of the constructor.
p
Yes. But if other fields are not copied, why data classes are allowed to inherit from such classes? It is confusing.
j
Data classes are also allowed to have properties outside their constructor, and those are not copied either. It applies to all generated methods:
equals
,
hashcode
,
toString
, and
copy
. They all only consider the parameters from the constructor. It's just how they are designed: > The compiler automatically derives the following members from all properties declared in the primary constructor
p
Thanks, but why it is allowed? It is confusing behavior.
e
c
Thanks, but why it is allowed? It is confusing behavior.
It's only confusing if the additional property are completely unrelated to the data in the primary constructor. But in this case, a
data class
is not the right abstraction. Here's an example with additional properties that is not confusing at all and works as expected:
Copy code
data class Foo(
    val prefix: String,
    val postfix: String,
) {
    val full by lazy {
        "$prefix${expensiveOperation()}$postfix"
    }
}
In this case,
copy
,
equals
,
hashCode
etc all work as expected. Data class really do represent "data". Their identity is the contents of the primary constructor. You shouldn't have anything outside the primary constructor that you want to be part of the data.
3
p
Thanks! Got it.