I'm currently working on an application that requires delegating function variables. I've encountered some problems when trying to do so. Here's the code of a minimal reproducible example:
package org.prismsus.tank
import kotlin.reflect.KProperty
fun addFunc(a : Int, b : Int) : Int {
return a + b
}
class Test{
inner class PrintFuncCall1{
operator fun getValue(thisRef: Any?, property: KProperty<*>): (Int, Int) -> Int {
fun temp(a : Int, b : Int) : Int {
println("Function ${property.name}")
return addFunc(a, b)
}
return ::temp
}
}
val delegatedFun1 : (Int, Int) -> Int by PrintFuncCall1()
inner class PrintFuncCall2<F : (Array<out Any>) -> R, R>{
operator fun getValue(thisRef : Any?, property : KProperty<*>) : (Array<out Any>) -> R{
fun temp(vararg params : Any) : R{
println("Function ${property.name}")
println("Params: ${params.joinToString()}")
return addFunc(params[0] as Int, params[1] as Int) as R
}
return ::temp
}
}
val delegatedFun2 : (Int, Int) -> Int by PrintFuncCall2()
}
fun main(){
val test = Test()
println(test.delegatedFun1(1, 2))
println(test.delegatedFun2(3, 4))
}
Here delegatedFun1
and PrintFuncCall1
worked fine. However, I tried to modify the delegate class to a generic class and found that this didn't work. Specifically, I got this compilation error for delegatedFun2
and PrintFuncCall2
:
Property delegate must have a 'getValue(Test, KProperty<*>)' method. None of the following functions is suitable:
public final operator fun getValue(thisRef: Any?, property: KProperty<*>): (Array<out Any>) -> ??? defined in org.prismsus.tank.Test.PrintFuncCall2
I don't quite get why getValue
requires thisRef
to be of type Test
, which is the type of the larger class. This is especially strange as I'm delegating a variable of type (Int, Int) -> Int
. Further, even if I tried to change the signature of getValue
to getValue(thisRef : Test, property : KProperty<*>)
, I got the following error:
Property delegate must have a 'getValue(Test, KProperty<*>)' method. None of the following functions is suitable:
public final operator fun getValue(thisRef: Test, property: KProperty<*>): (Array<out Any>) -> ??? defined in org.prismsus.tank.Test.PrintFuncCall2
Besides these, a minor question I have is about Kotlin's constrain mechanism to type parameters. My intention for PrintFuncCall2
is to mark F
as the type of the function, and R
as the return value of function F
. However, when changing the signature of getValue
from getValue(thisRef : Test, property : KProperty<*>) : (Array<out Any>) -> R
to getValue(thisRef : Test, property : KProperty<*>) : F
, I got this message from IDE on the line return ::temp
:
Required:
KFunction1<Array<out Any>, R>
Found:
F
Isn't that these two supposed to be the same thing?
You issue seems to be a type mismatch between the expected return type of the delegate and the type you are giving it on the property level.
Your delegate is supposed to return a function of type (Array<Any>) -> R
but you are annotating the property with (Int, Int) -> Int
. Array<out Any>
is equivalent to vararg Any
, but it does NOT mean "any function with any sort of parameters".
The error should go away by annotating the property like this:
val delegatedFun2: (Array<Int>) -> Int by PrintFuncCall2()
Unfortunately there's no way to annotate a type as being a function with any sort or number of parameters. You will need to use an array.