Why can't Kotlin auto cast generic type - kotlin

If you are familiar with unity3d, I'm trying to implement a similar pattern for unity components:
AddComponent<T>();
GetComponent<T>();
So I made this snippet in kotlin:
val map = mutableMapOf<Class<Any>,IComponent>()
fun <T : IComponent> addComponent(component : T){
map.put(component.javaClass,component)
}
fun <T : IComponent> getComponent(klazz : Class<T>): T {
return map.get(klazz)
}
First of all, I have to pass a class to the getComponent method, I can't infer the type from T like C# and I was wondering if there is a way to do this.
And most importantly, why is the method giving me a compile error saying the I'm returning IComponent where T is required, although I did say that T IS an IComponent?
I have to cast to T which is unsafe, this works perfectly fine in C# universe but I'm new to kotlin and I'm wondering if that's possible.

First of all, I have to pass a class to the getComponent method, I can't infer the type from T like C# and I was wondering if there is a way to do this
To be able do something like this the type have to be reified.
In your case it would be something like this:
inline fun <reified T : IComponent> getComponent(): T {
val klazz = T::class.java
// something-something that returns T
}
and most importantly, why is the method giving me a compile error saying the I'm returning IComponent where T is required, although I did say that T IS an IComponent
You said that the type T is IComponent, but not that IComponent is T. And the map contains IComponent as values. Some of them can be T, but there're no guarantee for compiler that they are. So compiler falls with error, and says it isn't sure you will get something of type T out of the map.
So you need to force cast result to the type:
return map.get(klazz) as T // in your case you will have to cast klazz to Class<Any>, btw
To make it castles you should define map as
val map = mutableMapOf<Class<*>,IComponent>()
instead of
val map = mutableMapOf<Class<Any>,IComponent>()
Also, it would be better to use optional type T? for getComponent, in pair with conditional cast as?.

Related

How mockk is able to return object wrapped in Result when returnArguments

I am still learning kotlin, and I am curious how is it possible that mockk is able to return some object T wrapped in Result<T>. For better understanding let analyse below example:
We have such method definition
fun save(toSave : Entity): Result<Entity>
when we mock such method using returnArguments like it is done below:
every { mocked.save(any()) } returnsArgument 0
Then method returns Result<Entity>, but logic says that Entity should be returned.
Looking into declaration of returnsArgument there is casting to generic type which in our case is Result<Entity>, but when I tried to do it in plain I had casting exception.
I assume some magic happens inside, but what magic is responsible for such thing?
Would it be done with any wrapping object or it is specific only to Result?
Result<T> is a value class and mockk has a value class support.
After many internal steps returnsArgument will wrap the argument n with the specified value class and will return it.
Would it be done with any wrapping object or it is specific only to Result?
All value classes are supported, not just Result<T>.
// supported
#JvmInline
value class ValueWrapper<out T> (val something: Any?)
// not supported
class SomeWrapper<out T> (val something: Any?)
Hope it helps.

Kotlin type is not inferred into generic function

I have a generic function to fetch/get any list out of the SharedPreferences. However, when I wanted to test, that it does not work, when I saved a list of say, Messages and ask for a list of say, Ints, it still worked. It just ignored the type I precised and returned a List of JsonObjects. When I debugged the whole code, I found, that apparently the function does not care about the inferred class type. I´ll first put here the code, so I can explain the problem:
fun <T> getListFromPreferences(preferences : SharedPreferences, key : String)
: MutableList<T> {
val listAsString = preferences.getString(key, "")
val type: Type = object : TypeToken<List<T>>() {}.type
val gson = SMSApi.gson
return gson.fromJson<ArrayList<T>>(listAsString, type)
?: ArrayList()
}
So, what I would expect, was, that when I call the function like this:
PreferenceHelper.getListFromPreferences<Message>(preferences, TEST_KEY)
the "type" variable in the above code should return List. However the result the debugger shows me is: java.util.List<? extends T>
I have absolute no idea, why the inferring does not work, but I´d really like it to work to ensure, what I am requesting is actually what I get, for obvious reasions.
Does anybody know a reason and a solution for this weird behaviour?
Due to type erasure, actual type information about T is lost, so basically this method returns List<Any?> (even if you pass Int as T).
To preserve the actual type, you need to declare this method with reified parameter:
inline fun <reified T> getListFromPreferences(preferences : SharedPreferences, key : String)
: MutableList<T> {
//...
}

How to make a generic function for enumValues<T> in Kotlin?

I struggle with providing a type as parameter for a procedure that uses the enumValues<MyEnum>() function.
Got it to work with reified but using inline functions all the way is no option for me.
fun <T: Enum<Trait>> traits(
selectionState: SnapshotStateMap<Trait, Boolean>
) {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}
My enums all derive from enum class Trait. So in fact I want to pass enum class TraitFoo: Trait, enum class TraitBar: Trait and so on into the function.
Cannot use 'T' as reified type parameter. Use a class instead.
Is the compile error I receive here. Any idea of solving this? I am somewhat confused why this is not working.
Looking at the implementation of enumValues:
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
I see it uses reified. That does mean the type has to be known at compile time. Therefore I can not pass a generic but need to pass an explicit type? Is that the issue?
If yes - is there another way to achieve this rather than using reified ?
If you want to be able to use T in your function as if it's a real type then it must be reified. And in order for a type parameter to be reified it must be part of an inline function. So you're going to need an inline function.
The next bit is figuring out the generics. You currently have:
<T : Enum<Trait>>
That means, due to the nature of enums, that T can't possibly be anything other than Trait. However, you have since clarified that Trait is not an enum but is actually an interface that's implemented by various enum classes. So what you really want is T to be bounded by both Enum<T> and Trait.
Given all this, I believe what you're looking for is the following:
inline fun <reified T> traits(
selectionState: SnapshotTraitMap<Trait, Boolean>
) where T : Enum<T>, T : Trait {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}

why there is 'by' for the extended class and reified in function define

coming across a sample with a class and a function and trying to understand the koltin syntax there,
what does this IMeta by dataItem do? looked at https://kotlinlang.org/docs/reference/classes.html#classes and dont see how to use by in the derived class
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
IMeta by dataItem {
override fun getType(): String = dataType ?: dataItem.getType()
fun getData(): DerivedData? = getDataItem()
private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
}
for the reference, copied the related defines here:
interface IMeta {
fun getType() : String
fun getUUIDId() : String
fun getDataId(): String?
}
class DerivedData : IMeta {
override fun getType(): String {
return "" // stub
}
override fun getUUIDId(): String {
return "" // stub
}
override fun getDataId(): String? {
return "" // stub
}
}
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
There is some good documentation on reified type parameters, but I'll try to boil it down a bit.
The reified keyword in Kotlin is used to get around the fact that the JVM uses type erasure for generic. That means at runtime whenever you refer to a generic type, the JVM has no idea what the actual type is. It is a compile-time thing only. So that T in your example... the JVM has no idea what it means (without reification, which I'll explain).
You'll notice in your example that you are also using the inline keyword. That tells Kotlin that rather than call a function when you reference it, to just insert the body of the function inline. This can be more efficient in certain situations. So, if Kotlin is already going to be copying the body of our function at compile time, why not just copy the class that T represents as well? This is where reified is used. This tells Kotlin to refer to the actual concrete type of T, and only works with inline functions.
If you were to remove the reified keyword from your example, you would get an error: "Cannot check for instance of erased type: T". By reifying this, Kotlin knows what actual type T is, letting us do this comparison (and the resulting smart cast) safely.
(Since you are asking two questions, I'm going to answer them separately)
The by keyword in Kolin is used for delegation. There are two kinds of delegation:
1) Implementation by Delegation (sometimes called Class Delegation)
This allows you to implement an interface and delegate calls to that interface to a concrete object. This is helpful if you want to extend an interface but not implement every single part of it. For example, we can extend List by delegating to it, and allowing our caller to give us an implementation of List
class ExtendedList(someList: List) : List by someList {
// Override anything from List that you need
// All other calls that would resolve to the List interface are
// delegated to someList
}
2) Property Delegation
This allows you to do similar work, but with properties. My favorite example is lazy, which lets you lazily define a property. Nothing is created until you reference the property, and the result is cached for quicker access in the future.
From the Kotlin documentation:
val lazyValue: String by lazy {
println("computed!")
"Hello"
}

What is the purpose of having bound class reference return a covariant type?

I'm playing with reflection and I came out with this problem. When using bound class reference via the ::class syntax, I get a covariant KClass type:
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
As I could learn from the docs, this will return the exact type of the object, in case it is instance of a subtype of T, hence the variance modifier.
However this prevents retrieving properties declared in the T class and getting their value (which is what I'm trying to do)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
I found that a solution is using javaClass.kotlin extension function on the object reference, to get instead the invariant type:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
This way, I get both the exact type at runtime and the possibility to consume the type.
Interestingly, if I use a supertype instead of a generic, with the latter method I still get access to the correct type, without the need of variance:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == Derived::class)
}
}
fun main(args: Array<String>) {
val derived = Derived()
foo(derived) // prints 'true'
}
If I got it correct, ::class is equal to calling the java getClass, which returns a variant type with a wildcard, while javaClass is a getClass with a cast to the specific type.
Still, I don't get why would I ever need a covariant KClass, when it limits me to only produce the type, given that there are other ways to access the exact class at runtime and use it freely, and I wonder if the more immediate ::class should return an invariant type by design.
The reason for covariance in bound ::class references is, the actual runtime type of an object the expression is evaluated to might differ from the declared or inferred type of the expression.
Example:
open class Base
class Derived : Base()
fun someBase(): Base = Derived()
val kClass = someBase()::class
The expression someBase() is typed as Base, but at runtime it's a Derived object that it gets evaluated to.
Typing someBase()::class as invariant KClass<Base> is simply incorrect, in fact, the actuall result of evaluating this expression is KClass<Derived>.
To solve this possible inconsistency (that would lead to broken type-safety), all bound class references are covariant: someBase()::class is KClass<out Base>, meaning that at runtime someBase() might be a subtype of Base, and therefore this might be a class token of a subtype of Base.
This is, of course, not the case with unbound class references: when you take Base::class, you know for sure that it's the class token of Base and not of some of its subtypes, so it's invariant KClass<Base>.