Home > Software design >  Kotlin Type Mismatch (interface is not resolved properly)
Kotlin Type Mismatch (interface is not resolved properly)

Time:03-23

I am using Ktorm and trying to create an abstract and generic DAO for my tables. In the end I get a type mismatch though and I don't see where I am wrong:

BaseEntity is an interface for an entity class with an id:

interface BaseEntity<T: Entity<T>>: Entity<T> {
    val id: Int
}

User (the ORM class):

interface User: BaseEntity<User>

IdTable (a table that has an int id as primary key):

open class IdTable<T : BaseEntity<T>>(tableName: String) : Table<T>(tableName) {
    val id = int("id").primaryKey().bindTo { it.id }
}

Users (SQL table):

object Users : IdTable<User>("users")

BaseDao:

open class BaseDao<E : BaseEntity<E>>(private val es: EntitySequence<E, IdTable<E>>)

UserDao implements the BaseDao:

class UserDao(val es: EntitySequence<User, IdTable<User>>) : BaseDao<User>(es)

Now as mentioned in the Ktorm docs I create an EntitySequence like

val Database.users get() = this.sequenceOf(Users)

and I want to create a UserDao:

userDao = UserDao(database.users)

But I get

Type mismatch.
Required:
EntitySequence<User, IdTable<User>>
Found:
EntitySequence<User, Users>

But Users is of type IdTable<User> as it inherits from it. Why does the compiler not know that?

CodePudding user response:

I don't know Ktorm, so I won't help you with that part, but your problem is caused by type variance. Yes, you are correct, Users can be safely used as IdTable<User>. But that doesn't mean EntitySequence<User, Users> can be used as EntitySequence<User, IdTable<User>>. T type parameter of EntitySequence is invariant which means it can't be safely cast neither up nor down.

In order to safely cast EntitySequence<User, Users> to EntitySequence<User, IdTable<User>>, T would have to be covariant, so it had to be marked as out parameter. But it isn't.

In fact, by looking at the definition of EntitySequence I believe T could/should be marked as out. Then you could do what you need without problems. Maybe this is just a bug/oversight in Ktorm.

If I'm correct and T could be covariant, then it should be also safe to fix your problem by making an unchecked cast:

userDao = UserDao(database.users as EntitySequence<User, IdTable<User>>)

A long-term solution would be to report this to Ktorm developers - ask them to mark T as out.

  • Related