Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

412
Views
¿Por qué tener la palabra clave cosificada en Kotlin, no es suficiente marcar una función en línea?

En Kotlin, dado que la palabra clave 'reificada' solo se puede usar para parámetros de tipo genérico de funciones en línea, ¿por qué tener la palabra clave reificada? ¿Por qué el compilador de Kotlin (al menos en el futuro) no puede considerar automáticamente todos los parámetros de tipo genérico de las funciones en línea como cosificados?

He visto que la gente entra en pánico cuando mira esta palabra 'reificada' y me pide que no complique el código. De ahí la pregunta.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Los parámetros de tipo cosificados requieren argumentos de tipo pasados en ellos para ser cosificados también. A veces es un requisito imposible (por ejemplo, los parámetros de clase no se pueden cosificar), por lo que hacer que todos los parámetros de las funciones en línea se cosifiquen de forma predeterminada haría imposible llamar a TODAS las funciones en línea en los casos en que ahora solo es imposible llamar a las que tienen un tipo cosificado. parámetros:

 inline fun<T> genericFun(x: T) {} inline fun<reified T> reifiedGenericFun(x: T) {} class SimpleGenericClass<T>() { fun f(x: T) { genericFun<T>(x) //compiles fine reifiedGenericFun<T>(x) //compilation error } }

ACTUALIZAR. ¿Por qué no inferir automáticamente "reificibilidad" según el contexto?

  1. Enfoque 1 (sugerido por @ Tenfour04): analice el código de la función en línea y considere su parámetro de tipo como cosificado si tiene llamadas T::class (también agregué llamadas is T ).
  2. Enfoque 2 (sugerido por @SillyQuestion): Considere todos los parámetros de tipo de las funciones en línea como cosificados de manera predeterminada; si conduce a un error de compilación en el sitio de uso, entonces recurra al tipo no cosificado.

Aquí hay un contraejemplo para ambos: "a" as? T La función con este cuerpo tendría una semántica diferente dependiendo de si su parámetro de tipo se declara o no (o, hipotéticamente, se infiere) como cosificado:

 inline fun<reified T> castToReifiedGenericType() = "a" as? T inline fun<T> castToSimpleGenericType() = "a" as? T fun main() { println(castToReifiedGenericType<Int>()) //null println(castToSimpleGenericType<Int>()) //a } /*PS unsafe cast ("a" as T) also have different semantics for reified and non-reified T, causing `ClassCastException` in the first case and still returning "a" in the latter.*/

Entonces, con el primer enfoque, la semántica cambiaría si agregamos una llamada sin sentido a T::class / is T en algún lugar dentro de la función en línea. Con el segundo, la semántica cambiaría si llamamos a esta función desde el nuevo sitio (donde T no se puede reified , mientras que antes era "reificable") o, por el contrario, eliminamos una llamada de este sitio (permitiendo que se reified ) .

La depuración de problemas que surgen de estas acciones (a primera vista, sin relación con la observación de cambios semánticos) es mucho más compleja y provoca pánico que agregar/leer una palabra clave reified explícita.

over 4 years ago · Santiago Trujillo Report

0

Como demuestra la respuesta de @ Михаил Нафталь, un tipo que se reified es muy limitante, por lo que es fundamental que el lenguaje requiera que sea explícito sobre exactamente qué tipos se deben cosificar. La reificación requiere que se conozca el tipo en el momento de la compilación, por lo que las funciones con tipos reificados solo se pueden llamar desde funciones donde ese tipo no es un tipo genérico no reificado.

Alguien podría argumentar, bueno, solo asumir que está cosificado si T::class se usa dentro de esta función en línea y, de lo contrario, tratarlo como no cosificado. Pero eso significaría que la firma de su función efectiva podría cambiar simplemente cambiando el contenido de la función sin cambiar su declaración. Eso haría muy fácil cambiar accidentalmente la firma de una función, lo cual es una receta para el desastre en el futuro. Por ejemplo, supongamos que tengo esta función:

 inline fun <T> registerList(list: List<T>) { // T is not reified myProtectedRegistryList.add(list) }

y así se usa en otros lugares de mi aplicación, o por usuarios de mi biblioteca como este:

 class Foo<T>(val data: List<T>) { init { registerList(data) } } // or fun foo(data: List<T>) { registerList(data) } // or class Bar<T> { var barRegister: (List<T>)->Unit = ::registerList }

Luego modifico mi función sin cambiar su declaración:

 // In hypothetical Kotlin with implicit reification, T is now reified: inline fun <T> registerList(list: List<T>) { // This line of code unchanged! myProtectedRegistryMap.put(T::class, list) }

Ahora he descifrado el código en todas partes donde se usó como uno de los ejemplos anteriores. Entonces, por el lenguaje que requiere que cambie la declaración para cambiar la firma, se ve obligado a pensar en el impacto externo de modificar su función. Usted sabe que si refactoriza la declaración de cualquier función, esa es la única forma en que su usabilidad se ve afectada en los sitios de llamadas.

La filosofía de diseño de Kotlin en este tipo de asuntos es ser conservador y requerir declaraciones explícitas. Es la misma razón por la que las interfaces funcionales deben marcarse explícitamente con la palabra clave fun incluso si actualmente solo tienen una única función abstracta, y las clases/funciones son definitivas de forma predeterminada.

over 4 years ago · Santiago Trujillo Report

0

Aceptando la respuesta de @Михаил Нафталь (la primera proporcionada y actualizada) con un cálido agradecimiento también a @Tenfour04. Solo pensé en agregar una respuesta (con suerte) más simplificada basada en mi comprensión de las respuestas proporcionadas, que aún sería esencialmente correcta:

  • Una definición práctica (pero puede no ser completa) de un 'tipo verificable' es que si el tipo es algo como List<T> , podemos evaluar T::class.java a partir de él. Tal tipo verificable probablemente no haya tenido borrado de tipo, eso es algo que el compilador de Java hace en los parámetros de tipo para reducir el tamaño del binario compilado. Parece que en la actualidad, hay ciertos casos en los que el borrado de tipo lo realiza el compilador de Java heredado, etc. y kotlin aún no proporciona una forma de personalizar eso (es decir, evitarlo en ciertos casos).
  • Desafortunadamente, solo a partir de la expresión List<T> no se puede determinar si el tipo es verificable o no. Es como si se pudiera haber agregado una palabra clave para que el desarrollador vea esto explícitamente, por ejemplo: List<nonerased T> and List<erased T> . Pero en la actualidad, el compilador detecta esto en función de dónde/cómo se definió T, de lo contrario, el lenguaje podría volverse demasiado detallado.
  • En las funciones no en línea, todos los parámetros de tipo genérico se vuelven no verificables (borrados), probablemente debido al borrado de tipo jvm en el momento de la compilación, en línea con el comportamiento habitual (o actualmente técnicamente aún no abordado) del compilador de Java.
  • Sin embargo, en funciones en línea, por ejemplo, inline fun <T> f1(list: List<T>){...} , hay una opción para declarar un tipo como reified T (lo que lo hace inline fun <reified T> f1(list: List<T>){...} ), lo que significa que aceptará solo el tipo de parámetros List<nonerased T> (que tienen esta palabra clave invisible 'nonerased' asociada con ellos), de lo contrario, dará un error de compilación. Entonces no borrará el tipo para T. Debido a esta verificación en tiempo de compilación, el usuario ahora puede proceder a usar T::class.java dentro de la función en línea, con la seguridad de que no obtendrá un error en tiempo de ejecución porque T se erased T , por lo que no se puede encontrar T::class.java .
  • La función en línea sin la palabra clave 'reificada' visible se comportará como una función no en línea y se borrará como de costumbre.
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!