https://kotlinlang.org logo
#language-evolution
Title
# language-evolution
c

christophsturm

03/19/2021, 10:20 AM
the syntax for function references currently does not allow to distinguish between two versions of an overloaded method
Copy code
import kotlin.reflect.KCallable

interface IImpl {
    fun method()
    fun method(number: Int, name: String)
    fun nonOverloadedMethod()
}

fun function(callref: KCallable<*>) {println(callref)}

function(IImpl::nonOverloadedMethod)
function(IImpl::method) // resolution ambiguity
I wonder how a syntax that makes that work could look like
🤔 1
e

elizarov

03/19/2021, 4:35 PM
I'm deeply curious on what's your use-case for having a
KCalleble<*>
type in your
function
. What are you really trying to do?
c

christophsturm

03/19/2021, 4:56 PM
its the api of a simple mocking library. like the old java mock libraries that used strings to describe a method but with a method reference to make it more refactoring friendly
e

elizarov

03/19/2021, 5:00 PM
I see. I don't have any ideas for a nice syntax. The only advice I can give -- don't do overloads where you plan to use reflection like that.
c

christophsturm

03/19/2021, 5:01 PM
it has a different api now thats looks like mockito, but i liked that i can just get a list of method calls, and assert on it with my favorite assertion library instead doing the asserting in the mock library
y

Youssef Shoaib [MOD]

03/19/2021, 11:09 PM
You can currently use a simple
val
in the middle to force only one of the overloads to be used like this:
Copy code
val func: (Int, String) -> Unit = IImpl::method
val func2: () -> Unit = IImpl::method
function(func)
function(func2)
e

elizarov

03/20/2021, 11:21 AM
It will not be
KCallable<*>
this way.
y

Youssef Shoaib [MOD]

03/20/2021, 12:02 PM
Oh true, well this works:
Copy code
import kotlin.reflect.KCallable
import kotlin.reflect.KFunction3
import kotlin.reflect.KFunction1
interface IImpl {
    fun method()
    fun method(number: Int, name: String)
    fun nonOverloadedMethod()
}
fun function(callref: KCallable<*>) {println(callref)}
fun main() {
    val func: KFunction3<IImpl, Int, String, Unit> = IImpl::method
    val func2: KFunction1<IImpl, Unit> = IImpl::method
	function(IImpl::nonOverloadedMethod)
	function(func)
	function(func2)
    println(func == func2)
}
c

christophsturm

03/20/2021, 1:18 PM
cool I just turned on my computer because i thought i could try something like that.
Copy code
fun <A,B> f(function: KFunction1<A,B>) = function
fun <A,B,C,D> f(function: KFunction3<A,B,C,D>) = function
function(f<IImpl, Unit>(IImpl::method))
function(f<IImpl, Int,String,Unit>(IImpl::method))
or maybe rename it to
castFun
Copy code
fun <A,B> castFun(function: KFunction1<A,B>) = function
fun <A,B,C,D> castFun(function: KFunction3<A,B,C,D>) = function
function(castFun<IImpl, Unit>(IImpl::method))
function(castFun<IImpl, Int,String,Unit>(IImpl::method))
great, I think I’ll use that to implement my original idea of mock library api
y

Youssef Shoaib [MOD]

03/20/2021, 1:21 PM
You could also have it as a
castFun1
and
castFun3
so that the type parameters are automatically inferred
c

christophsturm

03/20/2021, 2:03 PM
now my mocking library supports this syntax:
Copy code
val mock = mock<IImpl>()
            mock.function()
            mock.overloadedFunction()
            mock.overloadedFunction("string")
            mock.overloadedFunction(10)
            val calls = getCalls(mock)
            expectThat(calls).containsExactly(
                call(IImpl::function),
                call(IImpl::overloadedFunction),
                call(IImpl::overloadedFunction, "string"),
                call(IImpl::overloadedFunction, 10)
            )
(expectThat is just an assertion from #strikt)
2 Views