Hello everyone, I am new to kotlin and would like ...
# codereview
n
Hello everyone, I am new to kotlin and would like some help. I tried to implement a type safe version of the PropertyChangeAware example that is given in the kotlin documenation. Below you will find code which seems to work. However I would like to ask if there is a better way to implement getChangeListeners(). 1. I had to use KProperty.toString() for equality because when a delegate setValue comes in the KPRoperty is different to the one you get from myClass::prop1 2. I would also like to be able to check that the passed in KPRoperty is actually one that is being observed by PropertyChangeAware.observer Any help would be appreciated.
Copy code
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
import kotlin.reflect.jvm.javaField

open class PropertyChangeAware {
    private val changeListeners: MutableMap<String, MutableList<(KProperty<*>, Any, Any) -> Unit>> = mutableMapOf()

    // can I use something more accurate than toString() here
    private fun getChangeListeners(property: KProperty<*>) : MutableList<(KProperty<*>, Any, Any) -> Unit> {
        require(property.javaField?.declaringClass == javaClass, {"The property $property doesn't belong to $javaClass" })
        // Is there a way to check here if the property is for the same instance as this?
        return changeListeners.computeIfAbsent(property.toString(), { mutableListOf() })
    }

    protected val observer: (KProperty<*>, Any, Any) -> Unit = { property, oldValue, newValue ->
        getChangeListeners(property)
                .forEach({ it.invoke(property, oldValue, newValue) })
    }

    fun <T : Any> addPropertyChangeListener(property: KProperty<T>, listener: (KProperty<T>, T, T) -> Unit) =
        getChangeListeners(property)
                .add(listener as (KProperty<*>, Any, Any) -> Unit)

}

class MyClass(prop1: String, prop2: Int) : PropertyChangeAware() {
    var prop1: String by Delegates.observable(prop1, observer)
    var prop2: Int by Delegates.observable(prop2, observer)
}

fun main(args: Array<String>) {
    val myClass = MyClass("A", 3)
    myClass.addPropertyChangeListener(myClass::prop1, listener())
    myClass.addPropertyChangeListener(myClass::prop2, listener())
    myClass.prop1 = "B"
    myClass.prop2 = 10
}

private fun <T> listener(): (KProperty<T>, T, T) -> Unit = {
        prop, old, new -> run {
            println("$prop changed from $old to $new")
        }
    }