How to make generic extends data class - kotlin

I know I can do something like this:
interface ISpecialEnum{/*interace stuff*/}
fun <T> consumeSpecialEnum(enum: T)
where T:Enum<T>, T:ISpecialEnum{
//code
}
to force a function to accept only enums with a specific interface.
Is there anything in kotlin to check if a generic extends a data class? Like:
interface ISpecialDataClass{/*interface stuff*/}
fun <T> consumeSpecialDataClass(dataClass: T)
where T:DataClass<T>, T:ISpecialDataClass{
//code
}

You can check if your type T is a data class (and that it implements your interface) like so:
fun <T> func(param : T) where T : ISpecialInterface {
if (param::class.isData) {
// do stuff
}
}
If you only want to check if it's a data class, you should remove the 'where' clause, however, to ensure that the type T cannot be null, you need to replace fun <T> with fun <T : Any>, as just <T> defaults to <T : Any?>.

In contrast with enums, there is no common supertype for all data classes (excluding Any, which is a common supertype for absolutely all kotlin classes).
So, generally, this check can't be done in compile time (but it is possible in runtime via reflection API).

Related

Kotlin Factory Class with Generic outputs

I'm in the process of trying to port some code I wrote in Java over to Kotlin and I'm struggling mightily with some issues around generics. I quite commonly use a factory pattern in Java to return an instance of a generic interface that I want to call for a given type.
In Java I had this contract:
public Message<T extends Action> {
private List<T> actions;
..some other properties
}
And this interface:
public interface MessageConverter<T extends Action, M extends BaseModel> {
List<M> convertMessage(Message<T> message);
DataType getDataType();
}
And lastly this factory:
public class MessageConverterFactory {
//This gets populated via DI
private Map<DataType, MessageConverter> converterMap;
public <T extends Action, M extends BaseModel> MessageConverter<T, M> getMessageConverter(DataType dataType) {
return converterMap.get(dataType);
}
}
With all that in place, I was able to do things like this:
Message<T> message = mapper.readValue(messageString, type);
MessageConverter<T, M> messageConverter = messageConverterFactory.getMessageConverter(dataType);
List<M> dataModels = messageConverter.convertMessage(message);
I understand that I was abusing raw generic types in Java to an extent to make this happen, but I assumed there would be some way to still do a generic factory pattern like this.
However, no matter with I try with generic variance, star projections, etc. I cannot get Kotlin to accept any version of this code. The closest I got was down to the invocation of the generic converter's convertMessage call. It was failing because I was using star projections and attempting to restrict the type of T, but that was leading to the compiler thinking convertMessage accepts Message<Nothing>.
Is code like this possible in Kotlin? Or is there a similar alternative approach I should be using instead?
Thanks,
Jeff
The literal conversion of this to Kotlin is pretty simple, and the Java-to-Kotlin converter built in to IDEA would spit something like this out almost directly, given the equivalent Java code:
class Message<T: Action> {
private val actions: List<T> = TODO()
...
}
interface MessageConverter<T: Action, out M: BaseModel> {
fun convertMessage(message: Message<T>): List<M>
val dataType: DataType
}
class MessageConverterFactory(val converterMap: Map<DataType, MessageConverter<*, *>>) {
fun <T: Action, M: BaseModel> getMessageConverter(dataType: DataType): MessageConverter<T, M> {
return converterMap[dataType] as MessageConverter<T, M>
}
}
Note, the cast in getMessageConverter -- your Java code is doing the equivalent, without being explicit about it -- I believe the compiler would even spit out a warning about an unchecked assignment.
An alternative in Kotlin is to use an inline function with reified types to return the appropriate converter. For example, something like this:
inline fun <reified T: Action, reified M: BaseModel> converterOf(): MessageConverter<T, M> = when {
T::class == FooAction::class, M::class == BarModel::class -> TODO()
else -> error("No converter available for type ${T::class.simpleName} to ${M::class.simpleName}")
}

Can I resolve a generic type from another generic declaration in an interface?

Expect you have an interface like this:
interface MyInterface<T : BaseClass<I>, I> {
fun someMethod(param: I) : T
}
As you can see I use I as a parameter in someMethod. But actually I don't want to declare I when I implement this interface like this:
class BaseClassImpl : BaseClass<OtherClass>
class Impl : MyInterface<BaseClassImpl, OtherClass> {
override fun someMethod(param: OtherClass) {
TODO("Not yet implemented")
}
}
Theoretically it should be possible that the I generic can be resolved by the compiler without the additional declaration because it's provided by BaseClassImpl. So MyInterface<BaseClassImpl> should already provide enough information to resolve the necessary generic for someMethod().
Is there any way to achieve that in Kotlin?
It's impossile in Kotlin.
Language specification states:
There are two kinds of type inference supported by Kotlin.
Local type inference, for inferring types of expressions locally, in statement/expression scope;
Function signature type inference, for inferring types of function return values and/or parameters.
It can't infer type of one generic parameter based on the type of another (especially for supertype declaration, because it is a very base for building type constrains system).
You may declare typealiases (for each T) to avoid repating I each time you implement this interface:
typealias MyInterfaceForBaseClassImpl = MyInterface<BaseClassImpl, OtherClass>
class Impl : MyInterfaceForBaseClassImpl {
override fun someMethod(param: OtherClass) : BaseClassImpl {
//...
}
}
It is not about compiler resolving, but about enforcing, when you declare interface MyInterface<T : BaseClass<I>, I : OtherClass> , declaration expects two parameters, May be you can create OtherInterface with OtherClass embedded and use it while implementing instead of MyInterface
interface BaseClass<I: OtherClass>
interface OtherClass
interface MyInterface<I : OtherClass, T: BaseClass<I>> {
fun someMethod(param: I)
}
class BaseClassImpl: BaseClass<OtherClass>
interface OtherInterface<T: BaseClass<OtherClass>> : MyInterface<OtherClass, T>
class Impl : OtherInterface<BaseClassImpl> {
override fun someMethod(param: OtherClass) {
}
}

Instantiating classes from non-reified type parameters

I'm building an ORM for use with jasync-sql in Kotlin and there's a fundamental problem that I can't solve. I think it boils down to:
How can one instantiate an instance of a class of type T, given a
non-reified type parameter T?
The well known Spring Data project manages this and you can see it in their CrudRepository<T, ID> interface that is parameterised with a type parameter T and exposes methods that return instances of type T. I've had a look through the source without much success but somewhere it must be able to instantiate a class of type T at runtime, despite the fact that T is being erased.
When I look at my own AbstractRepository<T> abstract class, I can't work out how to get a reference to the constructor of T as it requires accessing T::class.constructors which understandably fails unless T is a reified type. Given that one can only used reified types in the parameters of inline functions, I'm a bit lost as to how this can work?
On the JVM, runtime types of objects are erased, but generic types on classes aren't. So if you're working with concrete specializations, you can use reflection to retrieve the type parameter:
import java.lang.reflect.*
​
abstract class AbstractRepository<T>
​
#Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
generateSequence<Type>(this) {
(it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
?.genericSuperclass
}
.filterIsInstance<ParameterizedType>()
.first { it.rawType == AbstractRepository::class.java }
.actualTypeArguments
.single() as Class<T>
​
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
​
fun main() {
println(IntRepository::class.java.repositoryType())
println(StringRepository::class.java.repositoryType())
println(FooRepository::class.java.repositoryType())
println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar
In your own CrudRepository you can add a companion object with an inline fun which is responsible to instantiate your repository by passing to it the corresponding class.
class MyCrudRepository<T> protected constructor(
private val type: Class<T>,
) {
companion object {
inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
}
fun createTypeInstance() = type::class.createInstance()
}

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

Is there a way to get the type of object that inherits an interface (or another class) in Kotlin?

I've got an interface IMyInterface with a method
fun myMethod(thing: T){}
I also have a class
class MyClass : IMyInterface{}
What I want is that when I implement the members of the interface it automatically sets the type T to be MyClass. Is there a way of doing that?
So, instead of writing
interface IMyInterface <T>{
fun myMethod(thing: T){}
}
class MyClass: IMyInterface<MyClass>{
override fun myMethod(thing: MyClass){} // <<<-- the type is set because I explicitly set it above
}
I want to have something like this:
interface IMyInterface{
fun myMethod(thing: T){}
}
class MyClass: IMyInterface{
override fun myMethod(thing: MyClass){} // <<<-- the template type <T> of the interface is resolved by the compiler by checking what type I provided in method signature (
}
Or maybe getting a type of the class implementing an abstract class.
What you are wanting to do is not possible. You want the compiler to "Magically" figure out what the template parameter is... think about it; how would it know - there is a potentially infinite subset of IMyInterface. It is not implied in your interface that the template type <T> is even of type IMyInterface, so it could literally be any type...
Here is another angle on the problem that may make it clear why the compiler cannot do this:
// The same interface as your example, but with extra method
interface IMyInterface{
fun myMethod(thing: T){}
fun myOtherMethod(thing: T){}
}
// The same implementation as before, except the extra method is overridden with a different type than the first method
class MyClass: IMyInterface{
// the template type <T> of the interface is resolved by the compiler by
// checking what type I provided in method signature (this is what you want compiler to do)
override fun myMethod(thing: MyClass){}
// Uh oh! How does the copmpiler resolve this? We just figured out that <T> was my class.
// So this method won't compile... why not just tell entire class what <T> is
// rather than trying to make all method signatures match up so the compiler can "infer" the type???
override fun myOtherMethod(thing: MyOtherClass) {}
}
class MyOtherClass : IMyInterface {
override fun myMethod(thing: MyOtherClass) = this
override fun myOtherMethod(thing: MyOtherClass) = this
}
There is another problem which Thomas Cook's answer doesn't cover: even if this was possible, you run into major problems with subtyping in at least two ways.
Let's assume a keyword Self which means what you want and
interface IMyInterface{
fun myMethod(thing: Self): Unit
}
Problem 1: You have a val x: IMyInterface = ... What can you pass to x.myMethod? Certainly not any IMyInterface, that would defeat the purpose. But the only thing which is guaranteed to have the same concrete type as x is... x (assuming no Self-returning methods).
Problem 2: Add class MySubClass : MyClass. It must have override fun myMethod(thing: MySubClass), right? But it also has to inherit override fun myMethod(thing: MyClass) from MyClass.