samedi 13 avril 2019

Kotlin idiomatic way to forward property from different class

As in example:

class A {    
    var value: String
    get() = "value"
    set(value) { println(value) }
}

class B {
    val a = A()
    var value = a.value
}

fun main(args: Array<String>) {
    B().value = "new value"
}

B.value is only initialized with A.value.get, so of course A.value.set is not called during assignment in the main function, and thus doesn't print the message to console.

What I look for is syntax that would allow to forward both get and set functions to new variable based on different object's property of the same type.

I managed to implement such delegate, but it relies on kotlin-reflect library (invoking getter and setter) and I would like to avoid that:

import kotlin.reflect.KProperty
import kotlin.reflect.KMutableProperty

class Forward<T> (private val originalProperty: KProperty<T>){
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

class ForwardMutable<T> (private val originalProperty: KMutableProperty<T>){
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        originalProperty.setter.call(value)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return originalProperty.getter.call()
    }
}

fun <T> forward(originalProperty: KProperty<T>) = Forward(originalProperty)
fun <T> forward(originalProperty: KMutableProperty<T>) = ForwardMutable(originalProperty)

class A {
    var value: String
        get() = "value"
        set(value) { println(value) }
}

class B {
    val a = A()
    var value by forward(a::value)
}

fun main(args: Array<String>) {
    B().value = "new value" // calls A.value.setter
}

Isn't there a build-in delegate for such purpose? If not, how can I avoid kotlin-reflect dependency?





Aucun commentaire:

Enregistrer un commentaire