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

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.

Related

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

Get property of a Kotlin reflected object with type Any

I have something like this
fun validate(obj1: Any) {
// Here I am getting the KClass of the object
val objKClass = obj1::class
// Here I am casting the object using KClass
val obj1Cast = objKClass.safeCast(obj1)
// Then I want to iterate over its properties
for (prop in objKClass.memberProperties) {
//And get one BigDecimal? value
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
This doesn't work, I get in relation to prop.get(obj1Cast):
Type mismatch.
Required:
Nothing
Found:
Any?
Is there another way to access the values of the memberProperties and cast them to BigDecimal? (for example) given an object with type Any as the input for my function?
Use generic type capture to solve this problem.
In your current code, prop is of type KProperty1<out Any, *>. This is because the type of obj1 is Any, so the type of objKClass is KClass<out Any>. There are no values that satisfy the type out Any when it's used as an input parameter, so you get a compile error.
The first step is to capture the type of obj1. We can do that by adding a generic type parameter for it, instead of using Any. Let's call the captured type T.
fun <T: Any> validate(obj1: T) {
val objKClass: KClass<out T> = obj1::class
val obj1Cast = objKClass.safeCast(obj1) ?: return
for (prop in objKClass.memberProperties) {
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
Now the type of prop is KProperty1<out T, *>. This gets us one step closer, but we still have a compile error. That's because out T can only be used for an output value, but we want to pass a T into a method parameter.
Luckily, the safeCast can help us, because it will narrow the type of the value so it exactly matches the type of the class. We just need to give it some help by using a second method to capture the exact type of the class. Let's call the narrower exact type T2.
// Here we capture the type of the object as T,
// and get its class as KClass<out T>
fun <T: Any> validate(obj1: T) {
validate(obj1, obj1::class)
}
// Here we narrow the type of the object from T to T2
fun <T: Any, T2: T> validate(obj1: T, type: KClass<T2>) {
val obj1Cast = type.safeCast(obj1) ?: return
for (prop in type.memberProperties) {
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
Now it works with no compilation errors. For more information on how this works, you can read about "generic type capturing".

Kotlin generic factories

I'm trying to create an AnimalFactory that returns generic factories for making different types of Animals, depending on the arguments passed to the AnimalFactory.
Here's the code:
interface Animal {
fun talk(): String
}
class Cow: Animal {
override fun talk(): String {
return "mooo"
}
}
class Cat: Animal {
override fun talk(): String {
return "miow"
}
}
class Dog: Animal {
override fun talk(): String {
return "bark"
}
}
object AnimalFactory {
fun <T: Animal> AnimalMakerFactory(type: String): AnimalMaker<T> {
val maker = when (type) {
"cat" -> CatMaker()
"dog" -> DogMaker()
else -> CowMaker()
}
return maker
}
}
interface AnimalMaker<out T: Animal> {
fun make(): T
}
class CatMaker: AnimalMaker<Cat> {
override fun make(): Cat {
return Cat()
}
}
class DogMaker: AnimalMaker<Dog> {
override fun make(): Dog {
return Dog()
}
}
class CowMaker: AnimalMaker<Cow> {
override fun make(): Cow {
return Cow()
}
}
I get a type exception:
Type mismatch.
Required: AnimalMaker<T>
Found: AnimalMaker<Animal>
I thought that AnimalMaker would solve this, but apparently not. Why is AnimalMaker<T> not of type AnimalMaker<Animal> here?
The return value of the function is AnimalMaker<T> and not AnimalMaker<Animal> because that’s what you declared as the return type. The variable maker is indeed an AnimalMaker<Animal> but that isn’t a match for what the function is supposed to return because T could be a subtype of Animal.
You declared your function as having a generic type of T: Animal. Generic types are always an input to the function. In this case, it doesn’t make sense to use a generic input to the function because there’s no way to enforce that the type given is a match for the input String it corresponds with. To make your function work, you can remove <T : Animal and declare that it returns AnimalMaker<Animal>.
A little more explanation. There are two reasons why you might want to use generics in a function signature.
Enforce input parameter types.
Determine the output type.
You might use generics for one or both reasons (but the second can only be done by itself in a useful way by using reified generics, except in very specific cases where the returned class won’t be producing anything).
In your case, your input generic is not used to enforce the input parameter since that is just a String. To use it for the second reason, you would have to cast your return value’s type to the unknown (to the compiler) type T which would be unsafe because there’s no way to know if the input type given at the call site is a valid match for the given input String. And if you expected the call site to pass the right type, it would be redundant and error prone to also require a matching String to be passed.
Edit:
If you know the input type at compile time, then you can do this with reified generics. Get rid of the String input. It would look like this:
object AnimalFactory {
inline fun <reified T: Animal> AnimalMakerFactory(): AnimalMaker<T> {
#Suppress("UNCHECKED_CAST")
return when (T::class) {
Cat::class -> CatMaker()
Dog::class -> DogMaker()
Cow::class -> CowMaker()
else -> error("No factory found for type ${T::class}.")
} as AnimalMaker<T>
}
}
// Example usage
val someCatFactory = AnimalFactory.AnimalFactoryMaker<Cat>()
val cat: Cat = someCatFactory.make()
Inside this function, it is up to you to match the types up correctly, or there will be a ClassCastException at runtime. It seems logically it should be able to automatically cast them, but the compiler isn't sophisticated enough (yet?).

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...

kotlin: list properties of any object - variance error

I'm trying to write a function that produces map of properties and values for any type
inline fun <reified T : Any> T.propertiesMap() {
for (property in this::class.memberProperties) {
property.get(this)
}
}
i get a compilation error in property.get(this) about
out-projected type [...] prohibits the use of 'public abstract fun get(receiver...
The issue is that this::class produces a KClass<out T> instead of KClass<T> which is what would be needed to use anything of type T in the property.get(...) call. So you can do an unchecked cast to do what you want:
fun <T : Any> T.propertiesMap() {
#Suppress("UNCHECKED_CAST")
for (property in (this::class as KClass<T>).memberProperties) {
property.get(this)
}
}
Which does not require the function to be inline nor reified type parameter. Otherwise you can change your function to use T::class instead of this::class to create a matching KClass<T>.
inline fun <reified T : Any> T.propertiesMap() {
for (property in T::class.memberProperties) {
property.get(this)
}
}
If you use the type you are reifying rather than an instance of that type the variance issue will go away. When you call T::class.memberProperties you get back a Collection<KProperty<T, *>> which is what I believe you want. On the other hand, if you call that on an instance (this) rather than a type, you get back a Collection<KProperty<out T, Any?>>, which is where your out-variance issue comes from.
inline fun <reified T : Any> T.propertiesMap() {
for (property in T::class.memberProperties) {
property.get(this)
}
}
Essentially, you need to do T::class rather than this::class in order to get the right kind of collection back. I've left your code as-is otherwise because I'm not clear on what you want this function to do, but I suspect you could drop the for loop in favor of a map call.