Kotlin Access Property Name from Delegate

697 Views Asked by At

I'm writing a saving system for my game using kotlin delegated properties.

Here is a small example

import kotlin.reflect.KProperty

object Test {
    val test: Int by no_prop { 10 } // I want this
    val testTwo: Int by prop(::testTwo) { 10 } // I don't want this if possible
}

inline fun <reified T : Any> Test.no_prop(initializer: () -> T) = TestProp<T>()

inline fun <reified T : Any> Test.prop(prop: KProperty<*>, initializer: () -> T): TestProp<T> {
    println("My saving key is ${this.javaClass.simpleName}.${prop.name}")
    return TestProp<T>()
}

class TestProp<T : Any> {
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = 10 as T
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {}
}

My game uses a string key for saved properties. Its always *callerClassName*.*propertyName*

I was wondering if its possible through my delegate extension functions or the TestProp class to access the name of the property is delegating?

Ex: It would be nice if the no_prop method could the property that called it was named "test"

val test: Int by no_prop { 10 }

The following is a workaround, but I'd like to avoid doing that for every property if possible

val testTwo: Int by prop(::testTwo) { 10 }
2

There are 2 best solutions below

2
On

You can. Whenever you create a delegate you implement the ReadOnlyProperty (or ReadWriteProperty):

public fun interface ReadOnlyProperty<in T, out V> {
    /**
     * Returns the value of the property for the given object.
     * @param thisRef the object for which the value is requested.
     * @param property the metadata for the property.
     * @return the property value.
     */
    public operator fun getValue(thisRef: T, property: KProperty<*>): V
}

When you try to access the value of the property to delegate to (val test: Int by no_prop { 10 } in your case) the getValue function will be called and you'll have access to the KProperty. It has a name field you can use for this purpose.

This works for class properties and local properties as well!

0
On

Turns out kotlin has a "provideDelategate" method that is called on creation of the delegated property. See https://kotlinlang.org/docs/reference/delegated-properties.html#providing-a-delegate

The following code works:

import kotlin.reflect.KProperty

object Test {
    val test: Int by prop { 10 } 
}

inline fun <reified T : Any> Test.prop(prop: KProperty<*>, initializer: () -> T) = TestProp<T>()

class TestProp<T : Any> {
    operator fun getValue(thisRef: Any?, property: KProperty<*>) = 10 as T
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {}

    // THIS IS CALLED ON INITIAL CREATION
    operator fun provideDelegate(thisRef: Any?, property: KProperty<*>): TestProp<T> {
        println("My saving key is ${thisRef.javaClass.simpleName}.${property.name}")
        return this
    }
}

fun main() {
    println(Test.test)
}