Search code examples
kotlinkotlin-generics

Why can't Kotlin smart cast between an interface and the generic type that is derived from it?


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?


Solution

  • 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