I’m currently struggling with this problem and hope to find some assistance from the Kotline experts here
I wonder why its not possible to pass the varargs array to another generic class even though the type arguments are the same? Calling generic functions works fine.
(1) Argument type mismatch: actual type is 'Array<CapturedType(out T)>', but 'Array<T (of class MyArray<T>)>' was expected.
(2) Argument type mismatch: actual type is 'Array<CapturedType(out T)>', but 'Array<T (of class MyArray2<T>)>' was expected.
(3) None of the following candidates is applicable: constructor<T>(value: Array<T>): MyArray3<T> constructor<T>(size: Int): MyArray3<T>
(4) Cannot use 'T' as reified type parameter. Use a class instead.
(5) Cannot use 'T' as reified type parameter. Use a class instead.
(6) Assignment type mismatch: actual type is 'MyArray<CapturedType(out T)>', but 'MyArray<T (of class MyList<T>)>' was expected.
(7) Argument type mismatch: actual type is 'Array<CapturedType(out T)>', but 'Array<T (of class MyList<T>)>' was expected.
(8) Assignment type mismatch: actual type is 'MyArray2<CapturedType(out T)>', but 'MyArray2<T (of class MyList<T>)>' was expected.
(9) Argument type mismatch: actual type is 'Array<CapturedType(out T)>', but 'Array<T (of class MyList<T>)>' was expected.
(10) Assignment type mismatch: actual type is 'MyArray3<CapturedType(out T)>', but 'MyArray3<T (of class MyList<T>)>' was expected.
It feels like most constructs in this example should be valid but I can’t get the outer Array<T> into my wrapper class without facing errors. MyArray3 shows a my preferred structure.
I currently try to build workarounds with unchecked casts and using Any but it starts to get pretty dirty. As the consuming code is generated I am a bit limited with the expressions I can write.
Unfortunately this breaks as soon you use T in methods which I plan to do.
@JvmInline
@Suppress("NOTHING_TO_INLINE")
value class MyArray<out T>(val value: Array<out T>) {
constructor(vararg values: T) : this(values)
inline operator fun get(index: Int): T = value[index]
inline operator fun set(index: Int, element: T) { // (1)
value[index] = element // (2)
}
}
class MyList<T> {
private var data: MyArray<T>
constructor(vararg items: T) {
this.data = MyArray(items)
}
operator fun get(index: Int): T = this.data[index]
operator fun set(index: Int, element: T) {
this.data[index] = element
}
}
(1) Type parameter 'T' is declared as 'out' but occurs in 'in' position in type 'T (of class MyArray<out T>)'.
(2) Receiver type 'Array<out T (of class MyArray<out T>)>' contains out projection which prohibits the use of 'fun set(index: Int, value: T): Unit'.
Platform declaration clash: The following declarations have the same JVM signature (constructor-impl([Ljava/lang/Object;)[Ljava/lang/Object;): fun <T> `constructor-impl`(value: Array<T#1 (type parameter of MyArray.`constructor-impl`)>): MyArray<T#2 (type parameter of MyArray)> defined in MyArray fun <T> `constructor-impl`(vararg values: T#2): MyArray<T#2> defined in MyArray
Platform declaration clash: The following declarations have the same JVM signature (constructor-impl([Ljava/lang/Object;)[Ljava/lang/Object;): fun <T> `constructor-impl`(value: Array<T#1 (type parameter of MyArray.`constructor-impl`)>): MyArray<T#2 (type parameter of MyArray)> defined in MyArray fun <T> `constructor-impl`(vararg values: T#2): MyArray<T#2> defined in MyArray
The type of values in varargs values: t is Array<out T>, which is why you can’t pass it to a function that expects Array<T>. And to create a new Array<T> in the constructor is hard because the code needs to know at compile time what type T is, and the constructor doesn’t have that information.