2

Let's say I have a data class that has three properties:

data class Product(
    val id: Int,
    val name: String,
    val manufacturer: String)

If I understand correctly, Kotlin will generate equals() and hashCode() using all the three properties, which will be like:

override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (other == null || javaClass != other.javaClass) return false
    val that = other as Product?
    return id == that.id &&
            name == that!!.name &&
            manufacturer == that.manufacturer
}

override fun hashCode(): Int {
    return Objects.hash(id, name, manufacturer)
}

So what if I don't want id to be used in equals() and hashCode()? Is there a way to tell Kotlin to ignore certain properties when generating these functions? How about toString() and compareTo()?

Sah
  • 1,017
  • 2
  • 11
  • 19
  • 1
    Same question, no good answer http://stackoverflow.com/q/29595301/3144601 – voddan May 20 '17 at 09:44
  • Possible duplicate of [Property include/exclude on Kotlin data classes](http://stackoverflow.com/questions/29595301/property-include-exclude-on-kotlin-data-classes) – yole May 20 '17 at 12:57
  • If you need custom `equals()` and `hashCode()` methods then you should make it a regular class and implement them yourself instead of a data class - it's a sign you're trying to use a `data class` for something that this feature wasn't designed for. – Jesper May 22 '17 at 11:58

3 Answers3

5

For data classes, these functions are generated using all the properties that are declared in the primary constructor. From the official documentation:

The compiler automatically derives the following members from all properties declared in the primary constructor:

  • equals()/hashCode() pair,
  • toString() of the form "User(name=John, age=42)",
  • componentN() functions corresponding to the properties in their order of declaration,
  • copy() function (see below).

If you want a property not to be taken into account for their implementation, you'll have to either move it out of the primary constructor, or implement these functions yourself.

More discussion about a similar issue here.

Community
  • 1
  • 1
zsmb13
  • 85,752
  • 11
  • 221
  • 226
2

A solution that has worked well for me is to separate your metadata from your data. e.g.:

data class Entity<out T>(val id: Int, val data: T)
data class Person(val name: String, val manufacturer: String)

Usage:

val e1 = Entity(1, Person("Mickey", "Disney"))
val e2 = Entity(2, Person("Mickey", "Disney"))
val e3 = Entity(3, Person("Donald", "Disney"))

e1 == e2
// false

e1.data == e2.data
// true

e2.data == e3.data
// false
mfulton26
  • 29,956
  • 6
  • 64
  • 88
0

From the documentation:

Note that the compiler only uses the properties defined inside the primary constructor for the automatically generated functions. To exclude a property from the generated implementations, declare it inside the class body.

Your example has to look like this:

data class Product(
    val name: String,
    val manufacturer: String) {
    val id: Int
}

For more information take a look at: https://kotlinlang.org/docs/reference/data-classes.html#properties-declared-in-the-class-body

McPringle
  • 1,939
  • 2
  • 16
  • 19