Reputation: 1650
I am trying to build a set of providers for realm objects. Here is an example structure I've tried to build:
Interface:
interface IDataProvider<out T : RealmObject> {
fun getRealmObject(): T
}
Base provider class with companion function for typed provider instantiation:
open abstract class BaseProvider<out T : RealmObject> constructor(protected val context: Context?) : IDataProvider<T> {
companion object {
fun <T : RealmObject, E : BaseProvider<T>> create(context: Context?): E {
if (something) {
return SomeChildProviderProvider(context)
} else {
throw TypeNotSupportedException()
}
}
}
}
And here is a child class:
class SomeChildProvider(context: Context?) : BaseProvider<ChildRealmModel>(context){
override fun getRealmObject(): ChildRealmModel {
throw UnsupportedOperationException("not implemented")
}
}
Problem I have is on the line
return SomeChildProviderProvider(context)
Type mismatch. Required: E. Found: SomeChildProvider.
I can't figure out why it does not see that E is actually SomeChildProvider. Thank you.
P.S. I know that I can cast it to E, but in my opinion, it should not be needed in this situation. Maybe I am missing something obvious here or probably lack of Kotlin knowledge.
UPDATE1: After the first answer, we have realized that code above does not make much sense since we have to define a type of returning provider and to pass it into create method. Initial idea was that create method returns some type which is BaseProvider subtype. Here are the changes I have made in order to support the initial idea:
IDataProvider
interface IDataProvider {
fun execute(realm: Realm)
fun createModel(realm: Realm): RealmObject
}
BaseProvider
open abstract class BaseProvider constructor(protected val context: Context?) : IDataProvider {
override fun execute(realm: Realm) {
realm.executeTransaction { r ->
createModel(r)
}
}
companion object {
fun create(context: Context?): IDataProvider {
if (something) {
return ChildProvider(context)
} else {
throw TypeNotSupportedException()
}
}
}
}
ChildProvider
class ChildProvider(context: Context?) : BaseProvider(context) {
override fun createModel(realm: Realm): ChildRealmModel {
var realmObject = realm.createObject(ChildRealmModel ::class.java)
//object property initialization
return realmObject
}
}
UI call
BaseProvider.create(context).execute(realm)
Although, createModel method returns RealmObject, it's instance will be of ChildRealmModel. What I don't like about it is that we have to inspect instance type and cast into if we need exact model somewhere else.
Upvotes: 1
Views: 2190
Reputation: 33829
Your code is not consistent.
In the function declaration you pledge to return E
, which is a subtype of BaseProvider<T>
and can be chosen by the user on the call site.
But in the implementation you return SomeChildProviderProvider
, which is of course a subtype of BaseProvider<T>
, but still can be totally unrelated to E
which was chosen by the user.
An example:
class AnotherChildProvider : BaseProvider<ChildRealmModel>(context) {...}
val x = BaseProvider.create<ChildRealmModel, AnotherChildProvider>(context)
What is the type of x
? According to the function signature, it must be AnotherChildProvider
. But inside the function you return SomeChildProviderProvider
, which CAN NOT be casted to AnotherChildProviderProvider
.
Upvotes: 1