Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin NDArray with a lambda constructor with generic return type

I'm trying to create a very simple generic NDArray class in Kotlin that takes a lambda expression as an init function.

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) {
    val values: Array<T> =  Array(i * j, f)
}

A typical usage would be:

fun main(args: Array<String>){
    val m = NDArray(4, 4, ::zero)
}

fun zero(i: Int) =  0.0

My problem is that the Kotlin compiler complains on the initialisation of values in the constructor

values = Array(i * j, f)

by saying "Cannot use 'T' as reified type parameter. Use class instead". Why ?

EDIT:

If I instead replace the Kotlin Array implementation with my own MyArray it compiles:

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) {
    val values: MyArray<T> =  MyArray(i * j, f)
}

class MyArray<T>(i:Int, init: (Int) -> T) {
    ...
}

Not sure why Kotlin treats MyArray differently from a regular Array when both have the same constructor ?

like image 674
Tomas Karlsson Avatar asked Feb 23 '16 15:02

Tomas Karlsson


1 Answers

Creating a Java array requires specifying an element type. In the case of your class, the element type is provided only as a type parameter of the class, and generics in Java are erased at runtime. Because of that, the element type of the array is not known, and it's not possible to create it.

If you would want to create a custom wrapper around standard Array<T>, it would have to look like the following:

class NDArray<reified T>(i:Int, j:Int, init: (Int) -> T) {
    val arr = Array<T>(i * j, init)
}

The reified keyword means that your T is not erased, and may be used in places where a real class is needed, like calling the Array() constructor.

Note that this syntax is not supported for class constructors, but it is still useful for factory functions (must be inlined)

fun <reified T> arrayFactory(i:Int, j:Int, init: (Int) -> T) = Array<T>(i * j, init)
like image 174
yole Avatar answered Sep 19 '22 02:09

yole