Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine whether the reified type is nullable

Tags:

kotlin

Suppose I have a delegate class that needs a class type and a Boolean. I have specific functionality in mind if the type of the property this delegate is used for is nullable. To keep it simple, let's say it's supposed to throw an error for nulls depending on the Boolean parameter.

class Sample<T: Any> (val type: KClass<T>,
                      val allowNulls: Boolean){
    private var value: T?

    operator fun getValue(thisRef: Any, property: KProperty<*>): T? {
        return if (allowNulls)
            value
        else
            value?: throw Exception("Value is null!")
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: T?) {
        this.value = value
    }
}

I want to create a reified function for easily generating an instance of this class that automatically determines whether the type should be nullable. Again, this is useful for a delegate that behaves differently for nullable properties. This would for example be used to allow different behavior depending on whether delegated properties were nullable:

val nullableString by sample<String?>()
val nonnullString by sample<String>()
val nullableString2: String? by sample()
val nonnullString2: String by sample()

How can I determine if the reified type is nullable? I don't see a way to access this information:

inline fun <reified T: Any> sample(): Sample<T>{
    return Sample(T::class, /** T is nullable */)
}
like image 426
Tenfour04 Avatar asked Nov 18 '19 21:11

Tenfour04


2 Answers

If T is a reified generic type parameter, you can find whether it's nullable or not with a simple, though not obvious at first sight check:

if (null is T) { 
   // T is nullable
}

However in your example T has Any upperbound, so the expression will always be false.

like image 131
Ilya Avatar answered Nov 13 '22 14:11

Ilya


There's a very simple answer to this!  But first:

Remember that the top type in Kotlin is Any? (which is nullable).  The non-nullable Any is a subtype, and all non-nullable types descend from that.  So a type is nullable if it's not a subtype of Any.

So your generic <reified T: Any> is already restricting to non-nullable types, and your function could just use false!

However, if you relax that restriction, the test becomes just null is T — after all, a type is nullable iff it includes null as a value:

inline fun <reified T: Any?> sample(): Sample<T> {
    return Sample(T::class, null is T)
}
like image 10
gidds Avatar answered Nov 13 '22 14:11

gidds