Instantiating generic array in Kotlin
generics, kotlin
Solution
JVM arrays, on which Kotlin arrays are mapped to, require the element type to be known at compile time to create an instance of array.
So you can instantiate `Array<String>` or `Array<Any>`, but not `Array<T>` where `T` is a type parameter, representing the type that is erased at compile time and hence is unknown. To specify that a type parameter must be known at compile time it is marked with `reified` modifier.
There are several options, what you can do in this situation:
Use `MutableList<T>` for storing elements, which doesn't require reified T:
// MutableList function, available in Kotlin 1.1
val data = MutableList(rows * cols, { i ->
val r = i / cols
init(r, i % cols)
})
// or in Kotlin 1.0
val data = mutableListOf<T>().apply {
repeat(rows * cols) { i ->
val r = i / cols
add(init(r, i % cols))
}
}
Create an array from an inline function with reified type parameter:
inline fun <reified T> Matrix2d(val rows: Int, val cols: Int, init: (Int, Int) -> T) =
Matrix2d(rows, cols, Array(rows * cols, { .... })
class Matrix2d<T>
@PublishedApi internal constructor(
val rows: Int, val cols: Int,
private val data: Array<T>
)
Use `Array<Any?>` as the storage, and cast its values to `T` in `get` function:
val data = Array<Any?>(rows * cols, { .... })
operator fun get(row: Int, col: Int): T = data[row * cols + col] as T
Pass a parameter of type `Class<T>` or `KClass<T>` to constructor and use java reflection to create an instance of array.
Problem
Why this doesn't compile? I get compile error in 3 line Cannot use T as reified type parameter. Use class instead ``` class Matrix2d<T>(val rows: Int, val cols: Int, init: (Int, Int) -> T) { var data = Array(rows * cols, { i -> val r = Math.floor(i.toDouble() / cols).toInt() init(r, i - r * cols) }) operator fun get(row: Int, col: Int): T = data[row * cols + col] operator fun set(row: Int, col: Int, v: T) = { data[row * cols + col] = v } } ``` Solution I added a factory function which looks like a second constructor but implemented in inline function ``` class Matrix2d<T>(val rows: Int, val cols: Int, private val data: Array<T>) { companion object { operator inline fun <reified T> invoke(rows: Int, cols: Int, init: (Int, Int) -> T): Matrix2d<T> { return Matrix2d(rows, cols, Array(rows * cols, { i -> val r = Math.floor(i.toDouble() / cols).toInt() init(r, i - r * cols) })) } } init { if (rows * cols != data.size) throw IllegalArgumentException("Illegal array size: ${data.size}") } operator fun get(row: Int, col: Int): T = data[row * cols + col] operator fun set(row: Int, col: Int, v: T) { data[row * cols + col] = v } } ```