hoge
hoge

Reputation: 43

Kotlin: Unchecked cast in my generic function

I'm trying to combine my two functions into one using generics.

fun <T> List<T>.toElementOrSize1(keySelector: (T) -> String): String {
    val key = keySelector(first())
    return if (all { keySelector(it) == key }) key else "size = $size"
}

fun <T> List<T>.toElementOrSize2(keySelector: (T) -> String?): String? {
    val key = keySelector(first())
    return if (all { keySelector(it) == key }) key else "size = $size"
}

I could write this:

fun <T, K : String?> List<T>.toElementOrSize(keySelector: (T) -> K): K {
    val key = keySelector(first())
    return if (all { keySelector(it) == key }) {
        key
    } else {
        "size = $size" as K
    }
}

This works, but I've got an unchecked cast warning.

Why was this warning issued? And how to avoid this warning?

Thanks.

Upvotes: 4

Views: 4630

Answers (1)

Tenfour04
Tenfour04

Reputation: 93521

The compiler isn't sophisticated enough to see that the only possible types for K are String and String? (since String is final), so to the compiler, K could be some other subtype of String? and so casting your literal String could be unsafe. And since K is a generic type, the casting is unchecked due to type erasure.

There are a number of situations like this that turn up when working with generics. It doesn't mean you've necessarily done something wrong, only that the compiler doesn't know enough to be sure you didn't. You can use @Suppress("UNCHECKED_CAST") before the function or statement to remove the warning and acknowledge that you know that it's a safe cast. This doesn't mean you're doing something hacky or poorly designed. It's used several times in the standard library source code.

Upvotes: 8

Related Questions