4

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.

Duncan McGregor
  • 17,665
  • 12
  • 64
  • 118

1 Answers1

4

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"))
Raman
  • 17,606
  • 5
  • 95
  • 112
  • I don't think it's a bug - the generic types of my function are satisfied by Any, so it compiles. The Array.fill example cited in your reference is also cited in the Kotin Generics documentation, but my attempts to use use-site variance have failed. – Duncan McGregor Oct 02 '16 at 06:34
  • I think we can hide the creation of the type-marshalling object behind a method call as in the answers to http://stackoverflow.com/q/39596420/97777 - which is I suspect really the same question – Duncan McGregor Oct 02 '16 at 20:18