El parámetro de tipo reificado Kotlin no se puede usar como parámetro de tipo en el cuerpo de la function

Un parámetro de tipo reificado en Kotlin evita el borrado de parameters de tipo y permite que el parámetro de tipo sea conocido en time de ejecución. Esto permite que el siguiente código se compile y ejecute como se esperaba:

inline fun <reified T> isA(value: Any) = value is T 

Sin embargo, cuando trato de usar "T" como un parámetro de tipo en lugar de ser independiente, recibo un post de que se trata de un tipo borrado. Esto se demuestra con el siguiente código que es solo para fines ilustrativos :

 inline fun <reified T> isListOfA(name: String): Boolean { val candidate = Class.forName(name) return candidate is List<T> } 

¿Esto se debe a una limitación técnica? Si es así, ¿cuál es esa limitación?

La limitación técnica que le impide hacer eso es el borrado de types generics en JVM . Básicamente, en el time de ejecución, un object de un tipo genérico List<T> convierte simplemente en una List que funciona con objects: solo en time de compilation se comtesting el tipo de security para asignaciones y llamadas a funciones. El parámetro de tipo real T está allí solo durante el time de compilation y luego se borra. No se puede restaurar en time de ejecución (al less por ahora: existe el Proyecto Valhalla que podría presentar generics reificados en time de ejecución para JVM un día).

En una function de Kotlin no en línea (y con un parámetro de tipo no reificado), ni siquiera podría hacer el primer tipo de verificación, el value is T , porque un parámetro de tipo ordinario se borrará también.

Con los parameters de tipo cosificado, el cuerpo de la function se inserta en sus sitios de llamada, con el parámetro de tipo real (o inferido) sustituido por T : cuando llama isA<String>("abc") , el sitio de llamada tendrá el bytecode con el instanceof verificación de String .

Pero incluso con los parameters de types reificados, no se puede introspectar los types generics: se puede verificar que something is List<*> pero no que something is List<String> : el argumento de tipo no se almacena en ningún lugar durante el time de ejecución.

También tenga en count que isA<List<String>>(listOf(1, 2, 3)) devolverá true . Así es como se maneja este extraño caso en Kotlin: solo la parte no genérica del tipo se puede verificar en time de ejecución, y así es.

no hay forma de hacerlo en Kotlin, ya que Java borra el parámetro de tipo genérico T en Tipo de Object / límite superior en time de compilation.

El primer enfoque que puede funcionar es porque el value is T se inserta en la function de sitio de llamada con tipo reificado, por ejemplo:

 //val is_string = isA<String>(1) // inline into the call-site function as below: val i:Int = 1 // v--- the actual type argument is inlined here val is_string = 1 is String 

Los types parametrizados siempre se borran en el time de ejecución. De modo que puede verificar que un valor sea una instancia T pero no una instancia T<V> , sin importar si T y V están reificados o codificados.

Sin embargo, incluso si eso fuera posible, su código de ejemplo no tiene sentido porque comtesting si el tipo con ese nombre es una instancia de Lista, en lugar de verificar si el tipo con ese nombre es el tipo de Lista esperado.

Si tiene una instancia de un object y desea verificar que sea una Lista que solo contenga elementos del tipo esperado, aún puede escribir algo como esto:

 inline fun <reified T> isListOfA(instance: Any) = instance is List<*> && instance.all { it is T } 

Evidentemente, no formulé mi pregunta de manera apropiada para get una respuesta del formulario que quería. La mayoría de las respuestas aquí son una variación de "porque no se puede hacer eso en Java". Bueno, tampoco puedes hacer x instanceof T en Java, pero puedes hacer x is T en Kotlin. Estoy buscando el obstáculo práctico subyacente, no la regla de Java. Las reglas están hechas para romperse, después de todo.

De mi comentario sobre la primera respuesta aquí, la pregunta reformulada es: si objectref is T puede hacerse funcionar en Kotlin por algún mecanismo X ¿por qué no puede objectref is SomeClass<T> se haga funcionar por ese mismo mecanismo?

tl; dr respuesta: Porque no habrá ningún object Class para SomeClass<T> en time de ejecución.

Respuesta más larga: Primero debemos entender el mecanismo X , que es generar una instanceof instrucción bytecode para is T Esta instrucción toma objectref y el nombre N de alguna class C , donde el comstackdor determina N desde el context. En time de ejecución, la class C derivada de N se usará para evaluar el objectref is T expresión objectref is T Para que esta evaluación ocurra, el object de class para C debe crearse una instancia. Entonces, para usar este mismo mecanismo para objectref is SomeClass<T> entonces N sería SomeClass<T> . Debido al borrado de tipo, no habrá un object de class para SomeClass<T> por lo que no es posible generar la instanceof instrucción necesaria y, por lo tanto, aplicar el mismo mecanismo. Además, la instanceof instrucción no puede tomar el nombre de la forma SomeClass<T> . Por lo tanto, si objectref is SomeClass<T> para que funcione, se debe encontrar e implementar otro mecanismo Y en Kotlin. Tal mecanismo puede o no existir.

Sé que algunos pueden decir que esto es lo mismo que algunas de las otras respuestas. Sin embargo, para bien o para mal mi estilo de aprendizaje es comprender cómo funcionan las cosas en el metal, y luego sintetizar esto contra el model abstracto. En este caso, la noción de borrado genérico de Java es el model abstracto (o parte de él). En realidad, "borrado" me parece blando a less que entienda al less una de las maneras en que se realiza en una implementación en funcionamiento.