Sobes.tech
Junior

¿Qué tipos de genéricos conoces?

sobes.tech AI

Respuesta de la IA

Invariante, covariante y contravariante.

  • Invariante: El tipo List<A> no es un subtipo de List<B> y viceversa, incluso si A es un subtipo de B. El tipo se mantiene exactamente.
  • Covariante (out): Permite usar subtipos. List<A> es un subtipo de List<B> si A es un subtipo de B. Se usa para parámetros de salida (valores devueltos).
fun foo(list: List<out Number>) {
    // Se puede leer del lista (Number, Double, Int, etc.)
    val number: Number = list[0]
    // No se puede añadir a la lista (no se sabe qué tipo de elementos se esperan)
    // list.add(1) // Error de compilación
}
  • Contravariante (in): Permite usar supertipos. List<B> es un subtipo de List<A> si A es un subtipo de B. Se usa para parámetros de entrada (argumentos).
fun foo(comparable: Comparable<in String>) {
    // Se pueden pasar argumentos String (o sus supertipos)
    val result = comparable.compareTo("hello")
    // No se puede obtener resultados de tipo String (no se sabe qué tipo de resultado)
    // val str: String = comparable.compareTo("world") // Error de compilación
}

En Kotlin estas conceptos se implementan con las anotaciones out y in en los parámetros de tipo. En Java se usan comodines (? extends para covarianza y ? super para contravarianza).

Tipo Propósito Palabra clave (Kotlin) Comodín (Java) Lectura permitida Escritura permitida
Invariante Coincidencia exacta de tipo No No
Covariante Uso de subtipos (productor - "out") out ? extends T No
Contravariante Uso de supertipos (consumidor - "in") in ? super T No