Reputation: 3209
I have the following class:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
return object : ViewIntent{} // type mismatch on this line
}
}
I receive a pre-compilation error stating:
Type mismatch
Required: I
Found: <S, I>
To fix this pre-compilation error I am casting the ViewIntent object to I:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): I {
@Suppress("UNCHECKED_CAST")
return object : ViewIntent{} as I
}
}
But why can't Kotlin detect that I
must be derived from ViewIntent
and smart cast it?
Upvotes: 2
Views: 1344
Reputation: 1573
Basically, the reason why what you're doing doesn't work is because whatever I
is is a subclass of ViewIntent
. Your object is also a subclass ViewIntent
. It's a completely different subclass. The cast you're doing is like trying to cast StringBuilder
into a String
.
Now let's discuss what I think you "want" to do and why that doesn't work either. In order to really get the result you want, you need to create the I
type directly, like this:
return object : I {}
And in we replaced that I
with an actual class,
return object : SomeClass {}
this would certainly fail, too. SomeClass
's constructor needs to be called, and you're not doing it. And there's no way to know what to pass into that constructor when using the generic type.
Upvotes: 1
Reputation: 15054
That's because ViewIntent
isn't I
. See example:
class MyViewIntent : ViewIntent
class MyPresenterActivity : PresenterActivity<..., MyViewIntent>() {
// inherited from PresenterActivity
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{} as MyViewIntent // you see where this breaks
}
}
Upvotes: 8
Reputation: 4673
It's just because "I" is NOT necessarily derived from ViewIntent, but exactly ViewIntent class.
You can fix it like this:
abstract class PresenterActivity<S : ViewState, I : ViewIntent> : AppCompatActivity() {
open fun initViewIntent(): ViewIntent {
return object : ViewIntent{}
}
}
Doing it your way is really unsafe.
To understand why, I guess you should start reading this:
https://blog.kotlin-academy.com/kotlin-generics-variance-modifiers-36b82c7caa39
https://kotlinlang.org/docs/reference/generics.html
https://proandroiddev.com/understanding-generics-and-variance-in-kotlin-714c14564c47
Upvotes: 5