2
votes

I want to know whether it's possible to force kotlin to infer the non-nullable of a given type inference. Consider the following example:

abstract class Wrapper<T>
class StringWrapper : Wrapper<String>()

fun <O, P> wrap(property: KProperty1<O, P>, wrapper: Wrapper<P>) {

}

When I call wrap on a non-nullable property, everything works fine:

data class NonNullableExample(val value: String)
wrap(NonNullableExample::value, StringWrapper())

But when I call wrap on a nullable property, I get a compiler error, because the inference of P is nullable, whereas StringWrapper isn't:

data class NullableExample(val value: String?)
wrap(NullableExample::value, StringWrapper())

Type inference failed: Cannot infer type parameter P in

fun <O, P> wrap(property: KProperty1<O, P>, wrapper: Wrapper<P>): Unit

None of the following substitutions

(KProperty1<NullableExample, String>, Wrapper<String>)

(KProperty1<NullableExample, String?>, Wrapper<String?>)

can be applied to

(KProperty1<NullableExample, String?>, StringWrapper)

So basically what I want is, regardless of P being nullable or non-nullable, P of Wrapper<P> should always be the non-nullable form of P. Is this possible?

1
Can you define a derived property from value but is non-nullable, and do NullableExample::NonNullableValue when calling wrap? Of course you'll need to deal with what happens when value is null, but you'll need to deal with that somewhere anyway, right?jingx

1 Answers

2
votes

So basically what I want is, regardless of P being nullable or non-nullable, P of Wrapper<P> should always be the non-nullable form of P.

That doesn't quite make sense as stated: there is just one P, not a separate one in Wrapper<P> and KProperty1<O, P>. So if you want them to be different, you can't use P for both.

But KProperty1 is covariant in the result type, so a KProperty1<O, P> is also a KProperty1<O, P?>. So if you change the signature to

fun <O, P : Any> wrap(property: KProperty1<O, P?>, wrapper: Wrapper<P>): Unit

it will accept both nullable and non-nullable properties:

wrap(NonNullableExample::value, StringWrapper())
wrap(NullableExample::value, StringWrapper())
// both compile