How to make a generic function for enumValues<T> in Kotlin? - 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)
}
}
}
}

Related

How to use #Serializable as a interface?

I would like to write an function, that would work on any object which is serializable. Something like this:
inline fun <reified #Serializable T> T.serialiseToJson(): String {
return format.encodeToString(this)
}
This doesnt work because you cant use #Serializable to annotate type parameter.
Is there a way to do this?
A common way to handle this is to take a serializer as a parameter.
fun <T> T.serializeToJson(serializer: KSerializer<T>): String {
return format.encodeToString(serializer, this)
}
It's a bit more verbose, but it's also more flexible because it allows the user to pass a custom serializer instead of always picking the generated one. And you have the same type-safety because you can only use it with types for which a KSerializer exists.

Why can't Kotlin auto cast generic type

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

Why are Kotlin reified functions better?

The official Kotlin docs and this answer do a great job of explaining how Kotlin reified allows us to change something like:
myJsonString.toData(MyDataClass::class)
To:
myJsonString.toData<MyDataClass>()
But I don't think either do a good job of explaining the motivation. Is the reified function only preferable because it saves a few characters? Or are there other benefits to not having to pass the class in as a parameter?
One more advantage of reified type parameters is that they provide full type information, including type arguments, when the type is known at compile time.
abstract class TypeReference<T> : Comparable<TypeReference<T>> {
val type: Type =
(javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
override fun compareTo(other: TypeReference<T>) = 0
}
inline fun <reified T: Any> printGenerics() {
val type = object : TypeReference<T>() {}.type
if (type is ParameterizedType)
type.actualTypeArguments.forEach { println(it.typeName) }
}
printGenerics<HashMap<Int, List<String>>>()
java.lang.Integer
java.util.List<? extends java.lang.String>
See: How to get actual type arguments of a reified generic parameter in Kotlin?
The other benefit is that the type parameter can be inferred. For example:
fun foo(myData: MyDataClass) { ... }
foo(myJsonString.toData()) // no need to specify MyDataClass at all
The motivation is type erasure in the end. Generics on the JVM are cool but only help at compile time. With reified, you can make generic types available at runtime. This results in cleaner APIs as demonstrated in this post and yole's answer, cleaner DSLs (they utilize reified a lot), and certainly also easier implementations that rely on type information which would be erased normally as shown by hotkey.

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

How to check generic type in Kotlin?

I have class:
class Generic<T : SuperType>() { ... }
And this code is't correct, but cast s to type T:
fun typeCheck(s: SuperType) {
when(s) {
is T -> // Do something
}
}
If use: s as T - this cast will show warning (unsafe cast).
How check that s is T type?
If you need to check if something is of generic type T you need to to have an instance of Class<T> to check against. This is a common technique in Java however in Kotlin we can make use of an inlined factory method that gets us the class object.
class Generic<T : Any>(val klass: Class<T>) {
companion object {
inline operator fun <reified T : Any>invoke() = Generic(T::class.java)
}
fun checkType(t: Any) {
when {
klass.isAssignableFrom(t.javaClass) -> println("Correct type")
else -> println("Wrong type")
}
}
}
fun main(vararg args: String) {
Generic<String>().checkType("foo")
Generic<String>().checkType(1)
}
Generic types are not reified on the JVM at runtime, so there's no way to do this in Kotlin. The warning is correct because the compiler can't possibly generate any instruction that will fail when the cast is done, so the cast is unchecked, meaning that the program may or may not break at some point later instead.
A related feature which might be of use is reified type parameters in inline functions. Classes can't have reified type parameters though, so if you elaborate a bit more on your use case, I can try helping you achieve what you seem to need.
I know that I'm kinda late to this thread, but I just want to recap on the answer provided by Alexander Udalov.
It is, indeed, impossible to determine the type of a generic parameter in Kotlin unless you're using inline functions and declaring the generic type as reified.
Not sure if I'll be able to answer this question entirely and accurately, but I feel like my contribution might still be valuable for someone who is attempting to do just that. So let's say you have a few data classes, and you want to check which type you're dealing with.
You could use a function like that:
inline fun <reified T> checkType() = when (T::class) {
TypeA::class -> println("TypeA")
else -> println("Type not recognized")
}
however, functions that call it must also be inline, so you might have to write something like
inline fun <reified T> someOtherFunction(data: T) {
checkType<T>
}
however, if you cannot allow for an inline function (let's say in an interface!), you can kinda 'cheat' the system by saying, for example
class AmazingTypes {
inline fun <reified T> checkType(genericParameter: T) = when (T::class) {
TypeA::class -> println("TypeA")
else -> println("Type not recognized")
}
}
fun myAwesomeMethod(someParameter: Any) {
val amazingClass = AmazingClass()
amazingClass.checkType(someParameter)
}
This is also example.
inline fun <reified T: ApiResponse> parseJson(body: String): T {
// handle OkResponse only
val klass = T::class.java
if (klass.isAssignableFrom(OkResponse::class.java)) {
return T::class.java.newInstance()
}
// handle others
return gson.from(body, T::class.java)
}