https://kotlinlang.org logo
Title
a

Adam S

02/12/2023, 9:20 PM
I’ve got a test util for managing a directory and creating files. I want to use a delegate to easily create files
testProject("foo") {
  var otherFileKt by projectFile("other_file.kt")
  otherFileKt = """
    // ...
  """.trimIndent()
}
but I keep getting
Property delegate must have a 'getValue(Nothing?, KProperty*>)' method. None of the following functions are suitable.
what’s wrong with my code?
delegateExample.kt.cpp
I always find the delegate stuff so confusing, and I don’t find the messages/suggestions from IntelliJ very helpful.
apparently sometimes the delegate needs to implement
ReadWriteProperty<Any?, String>
and sometimes
ReadWriteProperty<ProjectTest, String>
🤷‍♀️
delegate2.kt.cpp
g

Gleb Minaev

02/13/2023, 7:31 AM
First parameter of delegate operators is object which property the delegate is (if exists,
null
otherwise). So when you use it to delegate local variable (variable in lambda is also local variable) there is no object which property you delegate, so
thisRef
in
getValue
and
setValue
will be just
null
. To get contextual
ProjectTest
instance you need to provide it explicitly via receiver or context receiver of
projectFile
function. For example:
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

interface Project

fun project(arg: Project.() -> Unit) {}

class MyDelegate(project: Project, path: String) : ReadWriteProperty<Any?, String> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): String = TODO()
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) = TODO()
}

fun Project.file(path: String) : ReadWriteProperty<Any?, String> = MyDelegate(this, path)

fun main() = project {
    val myFile by file("path")
}