Primitive vararg failed to override generic vararg


#1

Define an interface with parameter T and a function with vararg.

interface Processor<T>{
    fun process(vararg index: T): Unit
}

Implement this interface as following:

class Impl : Processor<Int>{
    override fun process(vararg index: Int) {
        TODO("not implemented")
    }
}

compile it. we got Error: Kotlin: Class 'Impl' is not abstract and does not implement abstract member public abstract fun process(vararg index: Int): Unit defined in Processor.

If we change the Impl to this:

class Impl : Processor<Number>{
    override fun process(vararg index: Number) {
        TODO("not implemented")
    }
}

It compiles successfully.

Why could such thing happen and how to solve it?


#2

Probably what happens is that the system sees the Int type the vararg resolves to an array of primitives. Unfortunately an array of primitives is not compatible (at bytecode level) to an array of objects. It is still a compiler bug, and it should recognize that it is overriding and thus disable the optimization (Number is not a primitive type so you’re fine there) - or generate a synthetic method, but that’s expensive. The problem here is that the signature of Impl is now dependent on the signature of it’s parent (which is never the case in normal Java classes)


#3

Kotlin should probably generate two versions of the method in this case, like this Java code:

public Unit process(int... index) {
    TODO("not implemented")
}

@Override public Unit process(Integer... index) {
    this.process(toNativeArray(index))
}

#4

What I meant is that your toNativeArray is potentially expensive although kind of only if it was used to pass an array, not if actually used as vararg (who will ever pass a 100,000 parameters manually to a vararg function).

What I meant with the dependency thing is that normally method signatures are not dependent on the parent class. In this particular case they would be. I’m not sure whether that’s a real problem or not.


#5

What I meant with the dependency thing is that normally method signatures are not dependent on the parent class. In this particular case they would be. I’m not sure whether that’s a real problem or not.

I’m sure that is a problem, therefore I suggested to generally generate the two overloads.