Determine whether the reified type is nullable - 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 */)
}

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.

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)
}

Related

How to implement property delegate that works with an arbitrary type

I'm trying to implement custom property delegate to store props in a Map (just like in docs, for the educational purposes)
Delegate implementation must:
allow to store properties of arbitrary type
allow for type inference (just like the original one)
I've wrote a code that satisfies first condition:
import kotlin.reflect.KProperty
fun main() {
val e = Example(PropInMapDelegate())
e.myProp = 1;
println(e.myProp) // e.myProp is "Any?" :(
}
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp by propInMapDelegate
}
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun getValue(thisRef: Any, property: KProperty<*>): Any? {
return _map[property.name]
}
operator fun setValue(thisRef: Any, property: KProperty<*>, value: Any?) {
_map[property.name] = value
}
}
But, it has obvious 2 issues:
Using "Any?" breaks type inference
Explicitly specifying property type var myProp: Int by propInMapDelegate leads to errors:
error#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any?, KProperty<*>) defined in PropInMapDelegate
error#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any?, KProperty<*>, Any?) defined in PropInMapDelegate
I've tried to employ generics to allow for type inference, but failed.
Changing PropInMapDelegate implementation like so:
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun <T>getValue(thisRef: Any, property: KProperty<*>): T? {
return _map[property.name] as T // That feels very wrong
}
operator fun <T>setValue(thisRef: Any, property: KProperty<*>, value: T?) {
_map[property.name] = value
}
}
And using the following
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp: Int by propInMapDelegate // error (see below)
}
Leads to:
error#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any, KProperty<*>)   where T = Int for   operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T? defined in PropInMapDelegate
error#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any, KProperty<*>, Int?)   where T = Int for   operator fun <T> setValue(thisRef: Any, property: KProperty<*>, value: T?): Unit defined in PropInMapDelegate
Questions:
What am I missing?
Why does Kotlin expect the exact "Example" type in setValue/getValue signature?
How to implement "getValue" without using unsafe "as T" operator?
Edit: it seems that original implementation utilizes as too, so it's probably ok?
public inline operator fun <V, V1 : V> MutableMap<in String, out #Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
#Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
I think the error message is misleading you because of the way it is worded. "Example" isn't the part that doesn't match. Since Example is a subtype of Any, that part of your getValue() function signature is fine.
The part that doesn't match is that you are returning T? but you're trying to use it for a non-nullable property.
If you change your property to be nullable, it will work:
var myProp: Int? by propInMapDelegate
Or if you change your operator function to return a non-nullable, it will work:
operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T {
return _map[property.name] as T
}
Note that casting as T will fail if the value for that key doesn't exist in the map and you're using this for a non-nullable property, because null cannot be cast to a non-nullable T.
Regarding your question marked 3: As you can see in the standard library source code, casting is unavoidable if you are using a map of arbitrary value types. It's part of the potential danger in using a map for this purpose. It is also possible the map doesn't have the values at all that match up with the requested property names.

Kotlin nullable generic

I am not understand why this code not working
class nullableGenericA<T: Any?>{
fun someMethod(v: T){}
fun someMethod(){
someMethod(null)
}
}
error: "Null can not be a value of a non-null type T".
How it works? If nullable is not part of type why works this
class NullableGenericB<T>(val list: ArrayList<T>){
fun add(obj: T){
list.add(obj)
}
}
fun testNullableGenericB(){
NullableGenericB<String?>(ArrayList()).add(null)
}
Your generic type is not necessarily nullable. It only has an upper bound of allowing nullable, but it is not constrained to be nullable. Since T could possibly be non-nullable, it is not safe to pass null as T. For example, someone could create an instance of your class with non-nullable type:
val nonNullableA = NullableGenericA<String>()
If you want to design it so you can always use nullables for the generic type, then you should use T? at the use sites where it is acceptable. Then, even if T is non-nullable, a nullable version of T is used at the function site.
class NullableGenericA<T>{
fun someMethod(v: T?) {}
fun someMethod() {
someMethod(null)
}
fun somethingThatReturnsNullableT(): T? {
return null
}
}

Why do i need to specify constructor argument as nullable generic type?

I'm trying to make OK() to call ApiResponse constructor. When I give null to ApiResponse constructor argument, it shows error that type mismatches.
If I change data type to T? it works. Why is it happening? Default upper bound of T is Any? so i thought it won't be any problem to assign null.
class ApiResponse<T> private constructor(
val data: T, // If I change data type to T?, no error
val message: String?
) {
companion object {
fun <T> OK(): ApiResponse<T> {
return ApiResponse(null, null)
}
fun <T> OK(data: T): ApiResponse<T> {
return ApiResponse(data, null)
}
}
}
I've searched with keywords kotlin, generic, constructor, nullable, T but i could not find answer.
In
fun <T> OK(): ApiResponse<T> {
return ApiResponse(null, null)
}
if someone calls ApiResponse.OK<String>(), then it tries to construct an ApiResponse where data is null and also of type String, which is incompatible. None of your types prevent that call -- when you have a generic type argument to the function like that, the caller can specify any T they please, including a nonnull type.
You must either return an ApiResponse<T?>, or not have an argumentless OK factory method.

Is it possible to make safe inline Optional in Kotlin?

In Kotlin sometimes I have to work with double nullability. For example, I need double nullability, when I want to use T? where T may be a nullable type. There are a few approaches for doing this:
Holder<T>? where Holder is data class Holder<out T>(val element: T) - example1
boolean flag variable - example1
containsKey for Map<K, T?> - example1
The special UNINITIALIZED_VALUE for representing the second kind of null - example1
The last approach has the best performance, but it's also the most error-prone. So I've decided to encapsulate it in inline class Optional<T>:
inline class Optional<out T> #Deprecated(
message = "Not type-safe, use factory method",
replaceWith = ReplaceWith("Optional.of(_value)")
) constructor(private val _value: Any?) {
val value: T?
get() =
#Suppress("UNCHECKED_CAST")
if (isPresent) _value as T
else null
val isPresent: Boolean
get() = _value != NULL
companion object {
#Suppress("DEPRECATION")
fun <T> of(value: T) = Optional<T>(value)
fun <T : Any> ofNullable(value: T?): Optional<T> =
if (value == null) EMPTY
else of(value)
#Suppress("DEPRECATION")
val EMPTY = Optional<Nothing>(NULL)
}
private object NULL
}
inline fun <T> Optional<T>.ifPresent(code: (T) -> Unit) {
#Suppress("UNCHECKED_CAST")
if (isPresent) return code(value as T)
}
inline fun <T> Optional<T>.or(code: () -> T): T {
ifPresent { return it }
return code()
}
The first problem with this Optional is public constructor, which allows creating instances with arguments of not matching type.
The second problem was noticed at testing time. Here is the failed test:
emptyOr { Optional.EMPTY }.value assertEql null
fun <T> emptyOr(other: () -> T): T = Optional.EMPTY.or(other)
Exception:
Exception ClassCastException: Optional$NULL cannot be cast to Optional
at (Optional.kt:42) // emptyOr { Optional.EMPTY }.value assertEql null
If I remove inline modifier from Optional, the test will pass.
Q: Is there any way to fix these problems without removing inline modifier from Optional?
1 Examples include some context. Please read them fully before writing that I added incorrect links.
I implemented exactly the same utility in one of my projects: OptionalValue.kt. My implementation is very similar to yours, it is also an inline/value class, so it should be cpu/memory efficient and it passes all tests I throw at it.
Regarding your first question: about a public constructor. There is an annotation specifically for this case: #PublishedApi. I tried to reproduce ClassCastException from your example, but it worked for me without problems, so I believe it was a bug in Kotlin itself (?).
Also, to answer the question why do we need double nullability, I explained my point here

How to implement mutable optional in Kotlin?

I want a class which is equivalent to Java Optional but also
Properly handles null value ("Not set" state is different from "Null set")
Is mutable
Uses Kotlin built-in null-safety, type parameter can be either nullable or non-nullable which affects all methods.
Non-working code:
class MutableOptional<T> {
private var value: T? = null
private var isSet: Boolean = false
fun set(value: T)
{
this.value = value
isSet = true
}
fun unset()
{
isSet = false
value = null
}
fun get(): T
{
if (!isSet) {
throw Error("Value not set")
}
return value!! // <<< NPE here
}
}
fun f()
{
val opt = MutableOptional<Int?>()
opt.set(null)
assertNull(opt.get())
}
The problem is that if I try to set null, get() call fails with null pointer exception (caused by !! operator).
Some not-working proposals:
Do not use members of type "T?" in such class. I would not use it if I knew how to leave them uninitialized (not allowed by the compiler) or how to make them to have default initialization.
Use "fun get(): T?" (with nullable result). I want the result type to have the same nullability as the class type parameter. Otherwise there is no meaning in such null-safety if it is lost in a simple generic class, and I will need to set !! manually where I am sure it is non-nullable (the thing the compiler should ensure), making my code looking like wedge-writing.
Note: This example is synthetic, I do not really need the mutable optional, it is just a simple and understandable example, illustrating a problem I encounter occasionally with Kotlin generics and null-safety. Finding solution to this particular example will help with many similar problems. Actually I have a solution for immutable version of this class but it involves making interface and two implementation classes for present and non-present values. Such immutable optional can be used as type of "value" member but I think it's quite big overhead (accounting also wrapper object creation for each set()) just to overcome the language constraints.
The compiler wants you to write code that will be type-safe for all possible T, both nullable and not-null (unless you specify a not-null upper bound for the type parameter, such as T : Any, but this is not what you need here).
If you store T? in a property, it is a different type from T in case of not-null type arguments, so you are not allowed to use T and T? interchangeably.
However, making an unchecked cast allows you to bypass the restriction and return the T? value as T. Unlike the not-null assertion (!!), the cast is not checked at runtime, and it won't fail when it encounters a null.
Change the get() function as follows:
fun get(): T {
if (!isSet) {
throw Error("Value not set")
}
#Suppress("unchecked_cast")
return value as T
}
I got a similar issue. My use case was to differentiate null and undefined value when I deserialize JSON object. So I create an immutable Optional that was able to handle null value. Here I share my solution:
interface Optional<out T> {
fun isDefined(): Boolean
fun isUndefined(): Boolean
fun get(): T
fun ifDefined(consumer: (T) -> Unit)
class Defined<out T>(private val value: T) : Optional<T> {
override fun isDefined() = true
override fun isUndefined() = false
override fun get() = this.value
override fun ifDefined(consumer: (T) -> Unit) = consumer(this.value)
}
object Undefined : Optional<Nothing> {
override fun isDefined() = false
override fun isUndefined() = true
override fun get() = throw NoSuchElementException("No value defined")
override fun ifDefined(consumer: (Nothing) -> Unit) {}
}
}
fun <T> Optional<T>.orElse(other: T): T = if (this.isDefined()) this.get() else other
The trick: the orElse method have to be defined as an extension to not break the covariance, because Kotlin does not support lower bound for now.
Then we can define a MutableOptional with no cast in the following way:
class MutableOptional<T> {
private var value: Optional<T> = Optional.Undefined
fun get() = value.get()
fun set(value: T) { this.value = Optional.Defined(value) }
fun unset() { this.value = Optional.Undefined }
}
I am happy with my immutable Optional implementation. But I am not very happy with MutableOptional: I dislike the previous solution based on casting (I dislike to cast). But my solution creates unnecessary boxing, it can be worst...