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.