Reputation: 2243
So, I have some Java methods with these signatures (removed annotations and code body for the sake of simplicity):
public class JavaClass {
public static <E extends CharSequence> E join(E... array) { ... }
public static <E extends CharSequence> E join(CharSequence separator, E... array) { ... }
}
And I have some code in Kotlin, which calls the 'join' method:
class KtClass {
fun test(vararg array: String) {
JavaClass.join(*array)
}
}
So far so good; it will spread the varargs and call the former method signature. Okie dokie!
The problem comes if, for example, I want to call the latter method signature, with a 'separator' argument:
class KtClass {
fun test(vararg array: String) {
JavaClass.join("<br>", *array)
}
}
This code won't compile. The compiler can't get to decide which method to call. The error:
Error:(5, 13) Kotlin: Cannot choose among the following candidates without completing type inference: public open fun join(vararg array: String!): String! defined in JavaClass public open fun join(separator: CharSequence!, vararg array: String!): String! defined in JavaClass
I can't even name the arguments because Kotlin doesn't let argument naming for non-Kotlin functions.
EDIT: Replaced the E generic type parameter with plain String references in the Java method headers, and it worked! So I guess this to be an incompatibility of type inference with generic types or something like that?
I'm pretty sure this has to be something with the spread operator (*). But I can't pass the varargs parameter array
to the join
function if I don't use it.
How can I solve this without touching the Java code?
YES, I KNOW that there is Array.joinToString extension function, but this would solve only this particular case. I need to know a generic solution.
Upvotes: 5
Views: 5564
Reputation: 8495
tldr
Probably you work incorrectly with nullable types
I was struggling with this error for a while, but finally came up with a solution. I had this at first
user.items.apply {
removeAll(otherItems)
removeAll(otherItems2)
}
The items collection is a MutableSet? so it is nullable, and otherItems collections are nullable too. So after adding ? before the apply, and passing non nullable collection to the removeAll function, the errors disappeared.
user.items?.apply {
removeAll(otherItems.orEmpty())
removeAll(otherItems2.orEmpty())
}
Upvotes: 1
Reputation: 31264
It looks like you will need to create a helper class in Java to bridge the interop issue. e.g.:
public class JavaClassInterop {
public static <E extends CharSequence> E joinSeparatedBy(CharSequence separator,
E... array) {
return JavaClass.join(separator, array);
}
}
Then you can call both:
import JavaClass.join
import JavaClassInterop.joinSeparatedBy
fun main(args: Array<String>) {
join(*args)
joinSeparatedBy("<br>", *args)
}
Upvotes: 1
Reputation: 9963
I don't think that's Kotlin specific. The problem is that the generic argument, E
is of type CharSequence
so your call becomes something like join("separator", "word1", "word2")
which is, indeed, ambiguous since the first argument, of type E == CharSequence
is the same as the type of the other args.
Upvotes: 2