Explicitly answering question - You can use it by checking the E
class:
inline fun <reified E: Any> getArrayInline(key: String, defValue: Array<E>): Array<E>? {
return when(E::class) {
Int::class -> arrayOf(1, 2, 3)
String::class -> arrayOf("a", "b", "c")
else -> throw IllegalArgumentException("Invalid class: ${E::class.qualifiedName}")
} as Array<E>
}
But I discourage using it since:
- It's not type safe - you have to perform unsafe cast on the result and it can be called for any array type even if it's not included in the
when
cases
- it's inline - so this entire block of code is copied into bytecode whenever you use the method (see below)
- type checking is done at runtime, so it hurts performance
What happens when you use it? Let's check this example:
fun testArrayInline(){
val test = getArrayInline("key", emptyArray<Int>())
val test2 = getArrayInline("key2", emptyArray<String>())
}
Simple right? But once you look into generated bytecode it's not so good. For readablity this is Kotlin bytecode decompiled back into Java:
public static final void testArrayInline() {
String var1 = "key";
Object[] defValue$iv = new Integer[0];
KClass var3 = Reflection.getOrCreateKotlinClass(Integer.class);
Object var10000;
if (Intrinsics.areEqual(var3, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
var10000 = new Integer[]{1, 2, 3};
} else {
if (!Intrinsics.areEqual(var3, Reflection.getOrCreateKotlinClass(String.class))) {
throw (Throwable)(new IllegalArgumentException("Invalid class: " + Reflection.getOrCreateKotlinClass(Integer.class).getQualifiedName()));
}
var10000 = new String[]{"a", "b", "c"};
}
Integer[] test = (Integer[])((Object[])var10000);
String var7 = "key2";
Object[] defValue$iv = new String[0];
KClass var4 = Reflection.getOrCreateKotlinClass(String.class);
if (Intrinsics.areEqual(var4, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
var10000 = new Integer[]{1, 2, 3};
} else {
if (!Intrinsics.areEqual(var4, Reflection.getOrCreateKotlinClass(String.class))) {
throw (Throwable)(new IllegalArgumentException("Invalid class: " + Reflection.getOrCreateKotlinClass(String.class).getQualifiedName()));
}
var10000 = new String[]{"a", "b", "c"};
}
String[] test2 = (String[])((Object[])var10000);
}
It's pretty huge considering that function was called only twice with 2 cases in the "when" block. And it doesn't even do anything useful - you can already see the result of if
cases.
Correct way to do it - declare each type as separate non-inline functions:
fun getArray(key: String, defValue: Array<Int>) : Array<Int>{
return arrayOf(1, 2, 3)
}
fun getArray(key: String, defValue: Array<String>) : Array<String>{
return arrayOf("a", "b", "c")
}
You have to write slightly more code, but it does not have any of 3 issues I mentioned above.
You get very clean bytecode that way as well (small size, high performance), this is decompiled bytecode of same example as before but using non-inline functions:
public static final void testArray() {
String var3 = "key";
Integer[] var4 = new Integer[0];
getArray(var3, var4);
var3 = "key2";
String[] var5 = new String[0];
getArray(var3, var5);
}