Chenhe
Chenhe

Reputation: 1043

Kotlin: Compile error when CharSequence array and String array as argument

Here's my function:

fun setSingleChoiceItems(items: Array<CharSequence>?, checkedItem: Int,
        listener: DialogInterface.OnClickListener?) {
    // ...
}

I tried to invoke it with String array (converted from List):

val str = listOf("1", "2", "3")
dialog.setSingleChoiceItems(str.toTypedArray(), currentChoice, null)

My IDE gives no errors or warnings but I encountered a compilation error: None of the following functions can be called with the arguments supplied.

I tried to add an convenience function to accept String array:

fun setSingleChoiceItems(items: Array<String>?, checkedItem: Int,
        listener: DialogInterface.OnClickListener?) {
    // Here's a warning: No cast needed
    val cs = items?.map { it as CharSequence }?.toTypedArray()
    setSingleChoiceItems(cs,checkedItem,listener)
}

Now it can compile successfully but I encountered an IDE error: Overload resolution ambiguity. All these functions match.

It seems that the only correct way is to explicitly convert when calling -- without convenience method. Obviously this is very troublesome.

So what is the best way to solve this issue?

Upvotes: 4

Views: 258

Answers (1)

Tenfour04
Tenfour04

Reputation: 93834

You are using an invariant type for the array, so it can't accept both CharSequence and String. Assuming this function only reads from the array, you can make the type covariant. An Array<String> qualifies as an Array<out CharSequence> since String implements CharSequence.

fun setSingleChoiceItems(items: Array<out CharSequence>?, checkedItem: Int,
                         listener: DialogInterface.OnClickListener?) {
    // ...
}

However, if you also need to write to the array, it cannot be covariant. In that case, you can reference it in a generic way, and you will have to cast to the type, like this:

@Suppress("UNCHECKED_CAST")
fun <T: CharSequence> setSingleChoiceItems(items: Array<T>?, checkedItem: Int,
                         listener: DialogInterface.OnClickListener?) {
    // ...

    // If writing to the array, you must cast
    if (items != null) items[0] = "Hello" as T
}

Upvotes: 3

Related Questions