Skip to content

Instantly share code, notes, and snippets.

@cutiko
Last active September 10, 2019 21:20
Show Gist options
  • Save cutiko/2801b3cf4943cb30fb902052c5cf6326 to your computer and use it in GitHub Desktop.
Save cutiko/2801b3cf4943cb30fb902052c5cf6326 to your computer and use it in GitHub Desktop.
How does copy works on Kotlin

How does copy Kotlin works

In data class equals by default is structural there are exception like arrays (ArrayList will work, List as well, I have tested even with DateTime from JodaTime and it does work, but not arrays)

Output

lets see default behaviour
same ref defA and DEFb false
equals true
same ref defA and DEFc false
equals false
------------------------------------------------------------------------------
lets test model with good hashcode and good equals
same ref firstA and firstB false
equals true
same ref firstA and second false
equals false
lets copy firstA
same ref firstA and copyA false
equals true
------------------------------------------------------------------------------
lets test model with random id
same ref randomA and randomB false
equals false
lets copy randomA
same ref randomA and copyRandom false
equals false
------------------------------------------------------------------------------
lets test bad equals
same ref badA and badB false
equals false
lets copy badA
same ref badA and copyBad false
equals false
------------------------------------------------------------------------------
lets test default with instance inside
same ref defA and defB false
equals true
same ref defA and defC false
equals true
------------------------------------------------------------------------------
lets test default with array
same ref defA and defB false
equals false
------------------------------------------------------------------------------
lets test default with array but with overriden hashcode
same ref defA and defB false
equals true
------------------------------------------------------------------------------
lets test default list no overrides
same ref listA and listB false
equals true
same ref listA and listC false
equals true

Process finished with exit code 0
package copier
import java.util.*
class Copier {
companion object {
@JvmStatic
fun main(args: Array<String>) {
println("lets see default behaviour")
val defA = Default("def", 1)
val defB = Default("def", 1)
val defC = Default("defC", 2)
println("same ref defA and DEFb ${defA === defB}")
println("equals ${defA == defB}")
println("same ref defA and DEFc ${defA === defC}")
println("equals ${defA == defC}")
println("------------------------------------------------------------------------------")
println("lets test model with good hashcode and good equals")
val firstA = Model("first", 1)
val firstB = Model("first", 1)
val second = Model("second", 2)
println("same ref firstA and firstB ${firstA === firstB}")
println("equals ${firstA == firstB}")
println("same ref firstA and second ${firstA === second}")
println("equals ${firstA == second}")
println("lets copy firstA")
val copyA = firstA.copy()
println("same ref firstA and copyA ${firstA === copyA}")
println("equals ${firstA == copyA}")
println("------------------------------------------------------------------------------")
println("lets test model with random id")
val randomA = ModelWithRndId("random", 1)
val randomB = ModelWithRndId("random", 1)
println("same ref randomA and randomB ${randomA === randomB}")
println("equals ${randomA == randomB}")
println("lets copy randomA")
val copyRandom = randomA.copy()
println("same ref randomA and copyRandom ${randomA === copyRandom}")
println("equals ${randomA == copyRandom}")
println("------------------------------------------------------------------------------")
println("lets test bad equals")
val badA = ModelWithBadEquals("badA")
val badB = ModelWithBadEquals("badA")
println("same ref badA and badB ${badA === badB}")
println("equals ${badA == badB}")
println("lets copy badA")
val copyBad = badA.copy()
println("same ref badA and copyBad ${badA === copyBad}")
println("equals ${badA == copyBad}")
println("------------------------------------------------------------------------------")
println("lets test default with instance inside")
val now = Date().time
val date = Date(now)
val instanceA = DefaultWithInstance(date)
val instanceB = DefaultWithInstance(date)
val instanceC = DefaultWithInstance(Date(now))
println("same ref defA and defB ${instanceA === instanceB}")
println("equals ${instanceA == instanceB}")
println("same ref defA and defC ${instanceA === instanceC}")
println("equals ${instanceA == instanceC}")
println("------------------------------------------------------------------------------")
println("lets test default with array")
val arrayA = arrayOf("one", "two")
val withArrayA = DefaultWithArray(arrayA)
val arrayB = arrayOf("one", "two")
val withArrayB = DefaultWithArray(arrayB)
println("same ref defA and defB ${withArrayA === withArrayB}")
println("equals ${withArrayA == withArrayB}")
println("------------------------------------------------------------------------------")
println("lets test default with array but with overriden hashcode")
val overridenArrayA = DefaultWithArrayOverriden(arrayA)
val overridenArrayB = DefaultWithArrayOverriden(arrayB)
println("same ref defA and defB ${overridenArrayA === overridenArrayB}")
println("equals ${overridenArrayA == overridenArrayB}")
println("------------------------------------------------------------------------------")
println("lets test default list no overrides")
val seedA = listOf("one", "two")
val seedB = listOf("one", "two")
val listA = DefaultWithList(seedA)
val listB = DefaultWithList(seedA)
val listC = DefaultWithList(seedB)
println("same ref listA and listB ${listA === listB}")
println("equals ${listA == listB}")
println("same ref listA and listC ${listA === listC}")
println("equals ${listA == listC}")
}
}
}
package copier
data class DefaultWithList(val array: List<String>?)
package copier
data class Default(val name: String?, val age: Int?)
package copier
data class DefaultWithArray(val array: Array<String>?)
package copier
data class DefaultWithArrayOverriden(val array: Array<String>?) {
override fun hashCode(): Int {
return array?.contentHashCode() ?: 0
}
override fun equals(other: Any?) : Boolean {
return if (other !is DefaultWithArrayOverriden) false else (hashCode() == other.hashCode())
}
}
package copier
import java.util.*
data class DefaultWithInstance(val date: Date?)
package copier
data class Model(
val name: String?,
val age: Int?
) {
override fun equals(other: Any?) = if (other !is Model) false else (hashCode() == other.hashCode())
override fun hashCode(): Int {
var result = 31 * name.hashCode()
result += 31 * age.hashCode()
return result
}
}
package copier
data class ModelWithBadEquals(val name: String?) {
override fun equals(other: Any?) = false
override fun hashCode() = 0
}
package copier
import kotlin.random.Random
data class ModelWithRndId(val name: String?, val age: Int?) {
override fun equals(other: Any?) = if (other !is ModelWithRndId) false else (hashCode() == hashCode())
override fun hashCode() = Random.nextInt(1, 1000)
}
@cutiko
Copy link
Author

cutiko commented Sep 10, 2019

This is where the bug on the java compiler is mentioned

https://blog.jetbrains.com/kotlin/2015/09/feedback-request-limitations-on-data-classes/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment