Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Compare property values of different target objects with(out) reflection

I want to compare values between multiple instances of a data class so that I know which value changed:

data class A(val name : String)
val firstA = A("hello")
val secondA = A("you")

if (secondA.name.changed(firstA)) {
   // Do something
}

Can I somehow access the property function of .name and execute it on another target value (in this example on firstA) without explicitly defining it? Can delegates help here or how do I solve this with and without reflection?

like image 767
joecks Avatar asked Oct 17 '17 14:10

joecks


People also ask

How do you compare objects in Kotlin?

In Kotlin, == is the default way to compare two objects: it compares their values by calling equals under the hood. Thus, if equals is overridden in your class, you can safely compare its instances using ==. For reference comparison, you can use the === operator, which works exactly the same as == in Java.

Does Kotlin support reflection?

note. Kotlin/JS provides limited support for reflection features. Learn more about reflection in Kotlin/JS.

How do you set values on Kotlin?

In Kotlin, setter is used to set the value of any variable and getter is used to get the value. Getters and Setters are auto-generated in the code. Let's define a property 'name', in a class, 'Company'. The data type of 'name' is String and we shall initialize it with some default value.


1 Answers

Without Reflection

I found a way without using reflection:

interface DiffValue<T> {
    val old : T?
}

fun <T,R> T.changed(memberAccess : T.() -> R) : Boolean {
    if (this is DiffValue<*>) {
        val old = this.old as? T
        if (old != null) {
            val currentValue = with(this, memberAccess)
            val previousValue = with(old, memberAccess)
            return currentValue != previousValue
        }
    }
    return true
}

And this is how you use it:

data class A(val val name: String, override val old : A? = null)
val firstA = A("hello")
val secondA = A("you", firstA)

if (secondA.changed {name}) {
   // Do something
}

This is based on the concept of lambda literals with receivers that allows Kotlin to build powerful builders and DSLs.

Note: The DiffValue interface is optional and is just used to make it a bit easier to keep values together and avoids an additional parameter in changed.

like image 159
joecks Avatar answered Oct 04 '22 00:10

joecks