Search code examples
reflectionlambdakotlin

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?


Solution

  • 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 name: String, override val old : A? = null): DiffValue<A>
    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.