0

I try to call a custom Java collection from Kotlin, which implements an add(long value) method in this way:

public class SomeSet<T> {

    public void add(int value) {  }

    public void add(long value) {  }

    public void add(T value) {   }
}

In Java we can call the overloaded method without any problems:

SomeSet<Long> set = new SomeSet<Long>();
set.add(1);
set.add(1L);

But in Kotlin it seems to be impossible:

val set = SomeSet<Long>()
set.add(1 as Int)
set.add(1L) // ⚡ Overload resolution ambiguity
set.add(1L as Long) // ⚡ Overload resolution ambiguity

Complete compile error:

Overload resolution ambiguity. All these functions match.
public open fun add(value: Long): Unit defined in de.itscope.platform.producttracking.test.SomeSet
public open fun add(value: Long!): Unit defined in de.itscope.platform.producttracking.test.SomeSe

I already checked out suggests, for a very likely problem:
Kotlin: What can I do when a Java library has an overload of both primitive and boxed type?
But this doesn't helps here, whit this generic overloading.

ℹ This is not academic example. It's the way the com.google.zetasketch.HyperLogLogPlusPlus class is implemented. A HyperLogLog++ implementation from google out of the ZetaSketch library.

Bill Mair
  • 1,073
  • 6
  • 15
Tobse
  • 1,176
  • 1
  • 9
  • 22

2 Answers2

1

In Java we can call the overloaded method without any problems:

But this is only true because Long has different meaning in Java and in Kotlin. In Java it's java.lang.Long and SomeSet<Long> has methods add(long value) and add(java.lang.Long value). No conflict! Whereas Kotlin's kotlin.Long is closer to Java's long and so SomeSet<kotlin.Long> has two methods taking a kotlin.Long. So the equivalent of your working Java example is

val set = SomeSet<java.lang.Long>()
// if you want to call add(long)
set.add(1L)
// if you want to call add(T)
set.add(1L as java.lang.Long)  // or java.lang.Long(1L)

Kotlin will warn you that normally java.lang.Long should not be used in Kotlin, but in this case I think it's all right.

As an alternative, you don't necessarily need to change the type of set variable itself, just cast it when you want to call that method:

val s = SomeSet<Long>()
// if you want to call add(long)
(s as SomeSet<*>).add(1L)
// if you want to call add(T)
(s as SomeSet<Any>).add(1L as Any)

Playground (I haven't tested with a SomeSet actually defined in Java, but I don't expect the Kotlin equivalent to behave differently).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
0

The only hack I found to to call the add function is, to set Any as generic type:

val set: SomeSet<*> = SomeSet<Any>()
set.add(1)
set.add(1L)
Tobse
  • 1,176
  • 1
  • 9
  • 22