Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kotlin reified generic in virtual function

In my concrete class I would like to have a function that has the following signature.

inline fun <reified T : Comparable<T>> get(key: String): T

However I want to extract an interface for this class so I could swap implementations. However I'm not sure how to go about it as I can't mark virtual functions as inline.

So far I have this interface:

interface ModuleSettings {

    fun <T : Comparable<T>> get(key: String) : T

}

And this concrete class

class DefaultModuleSettings : ModuleSettings {

    override inline fun <reified T : Comparable<T>> get(key: String): T {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

But now the compiler complains that im trying to override the generic type with reified keyword. Is there any way I can achieve this pattern?

like image 440
Ben Avatar asked Feb 03 '20 10:02

Ben


2 Answers

You can't inline interface functions, but you can take the class object as a parameter. To still get the same function signature, you could create an inline reified overload in DefaultModuleSettings that delegates to the interface function. You can't call that if you only have a reference with the interface-type though.

Something like this:

interface ModuleSettings {
    fun <T : Comparable<T>> get(key: String, clazz: KClass<T>) : T
}

class DefaultModuleSettings : ModuleSettings {

    override fun <T : Comparable<T>> get(key: String, clazz: KClass<T>): T {
        TODO("not implemented")
    }

    inline fun <reified T : Comparable<T>> get(key: String): T = get(key, T::class)

}

Edit:

Making the inline function an extension function is better:

inline fun <reified T : Comparable<T>> ModuleSettings.get(key: String): T = get(key, T::class)
like image 177
marstran Avatar answered Nov 12 '22 00:11

marstran


I kind of achieved similar behavior with extension function:

interface ModuleSettings {

    fun <T : Comparable<T>> get(key: String, type: KClass<T>): T

}

inline operator fun <reified T : Comparable<T>> ModuleSettings.get(key: String) = get(key, T::class)


class DefaultModuleSettings : ModuleSettings {

    override fun <T : Comparable<T>> get(key: String, type: KClass<T>): T {
        TODO("not implemented") 
    }
}

It's not exactly what I'm was expecting to achieve, but it works semantically. However I would still consider it a hack

like image 25
Ben Avatar answered Nov 11 '22 22:11

Ben