I have a syntetic example of a problem I'm trying ...
# announcements
s
I have a syntetic example of a problem I'm trying to solve.
Copy code
class MyDelegatedProperty {
    var innerStr: String = ""

    operator fun getValue(thisRef: Any, property: KProperty<*>): String {
        return innerStr
    }
    operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        innerStr = value
    }

    fun doSomething() {
        println(innerStr)
    }
}

class Example {
    val str: String by MyDelegatedProperty()

    fun main() {
        // use the doSomething function from str
    }
}
Is this possible somehow? Can I access the object that is created by a delegated property?
m
I would imagine you can if your variable holds the delegate. Otherwise the compiler sees it as a String... unless you unsafe cast, I doubt it would let you.
s
you can if your variable holds the delegate
Sorry, did not understand you, what do you mean? Something like:
Copy code
val strDelegate = MyDelegatedProperty()
val str: String by strDelegate
Yes, it would work, but I want to shrink this declaration from two lines into one and somehow (using reflection?..) get the delegate object
m
Yes that's what I meant.
s
My whole goal is to make user just declare a delegated property and then in runtime use reflection to reach the delegate object and call its function
m
Have you tried to unsafe cast and call it?
s
No, but I don't see how it would work - it would just try to cast a String into a MyDelegatedProperty, isn't it?
m
I guess it depends on how it's implemented in the kotlin internals. One possibility is that your delegate dynamically subclass String, and your function is on the object but isn't visible at compile time. The cast would make it visible. I'm just guessing though, I have never tried something like this.
s
No, it does not work:
Copy code
import kotlin.reflect.KProperty

class MyDelegatedProperty {
    var innerStr: String = ""
    operator fun getValue(thisRef: Any, property: KProperty<*>): String {
        return innerStr
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        innerStr = value
    }

    fun doSomething() {
        println(innerStr)
    }
}

class Example {
    var str: String by MyDelegatedProperty()
}

fun main() {
    val example = Example()
    example.str = "test"
    ((example.str) as MyDelegatedProperty).doSomething() // java.lang.ClassCastException: class java.lang.String cannot be cast to class Line_1$MyDelegatedProperty (java.lang.String is in module java.base of loader 'bootstrap'; Line_1$MyDelegatedProperty is in unnamed module of loader org.jetbrains.kotlin.cli.common.repl.ReplClassLoader @3fe59f84)
	at Line_3.main(Line_3.kts:4)
}
👍 1
m
Alright, that's all I had sorry.
s
Anyways, thank you 😃
I found this method:
example::str.getDelegate() as MyDelegatedProperty
. But it throws
Exception in thread "main" kotlin.reflect.full.IllegalPropertyDelegateAccessException: Cannot obtain the delegate of a non-accessible property. Use "isAccessible = true" to make the property accessible
evem when I try to make it accessible:
Copy code
import kotlin.reflect.KProperty
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.reflect.jvm.javaGetter
import kotlin.reflect.jvm.javaSetter

class MyDelegatedProperty {
    var innerStr: String = ""
    operator fun getValue(thisRef: Any, property: KProperty<*>): String {
        return innerStr
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        innerStr = value
    }

    fun doSomething() {
        println(innerStr)
    }
}

class Example {
    var str: String by MyDelegatedProperty()

    fun doSomething() {
        Example::str.javaField!!.isAccessible = true
        Example::str.javaGetter!!.isAccessible = true
        Example::str.javaSetter!!.isAccessible = true
        ::str.isAccessible = true
        val delegate = ::str.getDelegate() as MyDelegatedProperty
        delegate.doSomething()
    }
}

fun main() {
    val example = Example()
    example.str = "test"
    example.doSomething()
}