How to stop Kotlin from widening types?

Viewed 47

So I'm trying to define a method like this


fun <R,F> myFunction(prop: KProperty1<R, F>, value:F)  {}


// so that the compiler only allows me to invoke it like 
myFunction(User::name, "Alejandro")
// and stops developers from doing illegal things like
myFunction(User::name, 123)

//However, compiler doesn't complain if I do that... it widens the type to Any

How can I achieve that?

1 Answers

Kotlin is "widening" the type here because the value type parameter (i.e. the second type parameter) of KProperty1 is defined with keyword out which makes that parameter covariant.

This means that for instance KProperty1<User, String> is a subtype of KProperty1<User, Any>, and hence User::name which is presumably a KProperty1<User, String>, can also be seen as a special case of KProperty<User, Any>. Therefore, it is totally legal to call myFunction<User,Any>(User::name, 123).

The logic behind this can be derived from the name of the out keyword: It is expected that the typed parameter is only used in "out position" of any function call. In the case of KProperty1 this makes sense, because it is the type of the return value of the property. When you get a value from a KProperty1<K, V>, that value is of type V and thus it can be used anywhere where it is okay to have some supertype of V.

This should only be a problem, if you want to use the value in the "in position" of some function, for instance, if you want to write a function that takes a value of type V and store it in a KProperty1<K, V>.

If this is what you want, you are lucky, because you can and should just use KMutableProperty1<K,V> where the value parameter does not have an out keyword which means that it is invariant. Also, that interface allows you to put the value into the property.

Changing your function definition to

fun <R,F> myFunction(prop: KMutableProperty1<R, F>, value:F)  {}

makes that the compiler allows myFunction(User::name, "Alejandro"), but it complains on myFunction(User::name, 123).

See also: Kotlin documentation on Variance

Related