Kotlin generics Array<T> results in "Cannot use T as a reified type parameter. Use a class instead" but List<T> does not
Looking at the declaration of emptyArray()
in the kotlin stdlib (jvm), we notice the reified
type parameter:
public inline fun <reified @PureReifiable T> emptyArray(): Array<T>
The reified
type parameter means that you have access to the class of T
at compile-time and can access it like T::class
. You can read more about reified
type parameters in the Kotlin reference. Since Array<T>
compiles to java T[]
, we need to know the type at compile-time, hence the reified
parameter. If you try writing an emptyArray() function without the reified
keyword, you'll get a compiler error:
fun <T> emptyArray() : Array<T> = Array(0, { throw Exception() })
Cannot use T as a reified type parameter. Use a class instead.
Now, let's take a look at the implementation of emptyList()
:
public fun <T> emptyList(): List<T> = EmptyList
This implementation doesn't need the parameter T
at all. It just returns the internal object EmptyList
, which itself inherits from List<Nothing>
. The kotlin type Nothing
is the return-type of the throw
keyword and is a value that never exists (reference). If a method returns Nothing
, is is equivalent to throwing an exception at that place. So we can safely use Nothing
here because everytime we would call EmptyList.get()
the compiler knows that this will return an exception.
Bonus question:
Coming from Java and C++, I am used to ArrayList
or std::vector
to be far easier to use that arrays. I use kotlin now for a few month and I usually don't see a big difference between arrays and lists when writing source code. Both have tons of usefull extension functions which behave in a similar way. However, the Kotlin compiler handles arrays and lists very different, as Java interoperability is very important for the Kotlin team. I usually prefer using lists, and that's what I'd recommend in your case too.
The problem is that the generic type of an Array
must be known at compile time, which is indicated by the reified
type parameter here, as seen in the declaration:
public inline fun <reified @PureReifiable T> emptyArray(): Array<T>
It's only possible to create concrete arrays like Array<String>
or Array<Int>
but not of type Array<T>
.
In this answer, you can find several workarounds.