Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I link the generic types of two Kotlin function parameters?

I want to write something like

fun <T, R> check(thing: T, property: KProperty1<T, R>, value: R) = 
    property.get(thing) == value

so that

assertTrue(check("Hello", String::length, 5))

but

assertTrue(check("Hello", String::length, "banana"))

doesn't compile.

like image 462
Duncan McGregor Avatar asked Oct 29 '25 11:10

Duncan McGregor


1 Answers

This seems to be an issue with Kotlin's type inference (though whether it is a bug or by design, I don't know). For example, if the types are explicit, this does not compile:

check<String, Int>("Hello", String::length, "banana")

It is probably designed to work like Java's generic method type inference, which allows this because the compiler infers a common super-type of R and T for both parameters. See Why doesn't type argument inference fail when I provide inconsistent method arguments?

According to the post above, in Java 5, 6, and 7 you could probably declare it like

fun <T, R, R1: R> check(thing: T, property: KProperty1<T, R>, value: R1) = 
    property.get(thing) == value

and the call with inconsistent params would not compile (I haven't tried it). However, this was considered a bug and in Java 8 the call with inconsistent params still compiles (I tried it).

In any case, you could wrap it in a class to avoid the inference and tie the type parameters together:

class Checker<T, R>(val property: KProperty1<T, R>)  {
  fun check(thing: T, value: R) =
    property.get(thing) == value
}
assertTrue(Checker(String::length).check("Hello", 5))
// does not compile
assertTrue(Checker(String::length).check("Hello", "banana"))
like image 181
Raman Avatar answered Nov 01 '25 04:11

Raman