La línea del tiempo: de 1.0 a 2.4
Los hitos que definieron Kotlin —corrutinas, multiplataforma y el compilador K2—, qué significa exactamente cada número de versión, y cómo funciona la política de estabilidad y de soporte de seguridad.
La historia de versiones de un lenguaje no es trivia: es el registro público de sus compromisos. Cada número de Kotlin codifica una promesa concreta sobre qué se puede romper y qué no, y cada hito —las corrutinas, el soporte multiplataforma, la reescritura del compilador— fue una apuesta que tardó años en cobrarse. Leer bien esa línea del tiempo te dice qué esperar de la 2.4 y qué no.
- Situar los hitos de Kotlin desde la 1.0 hasta la 2.4 y entender qué resolvió cada uno.
- Interpretar qué significa cada componente de un número de versión de Kotlin.
- Distinguir los niveles de estabilidad y el ciclo de deprecación en dos fases.
- Aplicar la política de soporte de seguridad de dieciocho meses vigente desde la 2.4.
De 1.0 a 1.9: la década de la compatibilidad
Kotlin 1.0 llegó en febrero de 2016, casi cinco años después del anuncio. Ese retraso fue deliberado: la 1.0 era el punto a partir del cual JetBrains se comprometía con la compatibilidad hacia atrás, y no quisieron firmar ese contrato antes de tiempo.
Los movimientos que definieron la rama 1.x:
- 1.1, en 2017. Las corrutinas entran como característica experimental y aparece el objetivo JavaScript. Ese mismo año, en mayo, Google anuncia soporte oficial de Kotlin en Android; en 2019 pasa a ser la estrategia Kotlin-first.
- 1.2, en 2017. Primer soporte experimental de proyectos multiplataforma, con el mecanismo
expectyactualpara declarar en común e implementar por objetivo. - 1.3, en octubre de 2018. Las corrutinas se declaran estables. Es el hito conceptual más importante del lenguaje: la concurrencia estructurada deja de ser una biblioteca prometedora y se vuelve infraestructura.
- 1.5, en 2021. El nuevo backend de JVM basado en IR pasa a ser el predeterminado, y llega el soporte para
recorde interfaces selladas de la plataforma. Aquí empieza a verse la arquitectura que después hará posible K2. - 1.6 a 1.9, entre 2021 y 2023. El nuevo frontend avanza en público de alfa a beta mientras el lenguaje añade cosas visibles como los tipos definitivamente no anulables y la estabilización progresiva del soporte multiplataforma.
flowchart LR A[1.0 en 2016: compatibilidad garantizada] --> B[1.3 en 2018: corrutinas estables] B --> C[1.5 en 2021: backend IR por defecto] C --> D[1.9 en 2023: K2 en beta] D --> E[2.0 en 2024: K2 estable] E --> F[2.4 en 2026: soporte de seguridad de 18 meses] style B fill:#a6e3a1,color:#11111b style E fill:#89b4fa,color:#11111b style F fill:#f9e2af,color:#11111b
Los tres hitos y por qué son distintos entre sí
Las corrutinas resolvieron la concurrencia sin introducir un tipo monádico. En vez de obligarte a envolver los resultados en un contenedor como haría un lenguaje puro, el compilador transforma cada función suspend a estilo de paso de continuaciones. La firma no cambia de forma: sigue devolviendo String, no un Future<String>. El coste de esa elegancia es que el mecanismo vive en el compilador, no en la biblioteca.
suspend fun cargarPerfil(id: Long): Perfil {
val datos = api.pedirDatos(id) // se suspende, no bloquea el hilo
val avatar = api.pedirAvatar(id)
return Perfil(datos, avatar)
}
El soporte multiplataforma fue el hito más lento porque no era un problema de lenguaje sino de ecosistema: hacían falta compilador, biblioteca estándar común, integración con Gradle y bibliotecas de terceros. Su estabilización llegó por partes a lo largo de la rama 1.9, y la adopción real vino después, cuando la capa de interfaz de usuario compartida entre Android e iOS dejó de ser experimental.
K2 es de otra naturaleza. No añadió sintaxis: reescribió el frontend del compilador, la parte que resuelve nombres, infiere tipos y comprueba errores. El modelo interno anterior estaba acoplado al bytecode de la JVM y era el cuello de botella para todo lo demás. K2 lo sustituye por una representación intermedia unificada, con dos consecuencias medibles: la compilación se acelera de forma notable en proyectos grandes, y las novedades del lenguaje dejan de tener que implementarse cuatro veces, una por objetivo. Fue alfa en la 1.7, beta en la 1.9 y el compilador predeterminado desde la 2.0, en mayo de 2024.
Qué significa cada número
Kotlin usa tres componentes con significados distintos, y confundirlos lleva a decisiones de actualización equivocadas.
- El primer número es el contrato del lenguaje. El salto de 1.9 a 2.0 no fue marketing: señalizaba el cambio de compilador y el nuevo punto de partida de compatibilidad.
- El segundo número es una versión de características. Cada una puede añadir sintaxis, marcar cosas como obsoletas y cambiar comportamiento del compilador, siempre dentro del ciclo de deprecación.
- El tercer número solo corrige errores. Nunca introduce características ni rompe nada.
Hay además dos ajustes que conviene conocer pronto porque separan el lenguaje que escribes de la biblioteca contra la que compilas. La opción -language-version fija qué construcciones acepta el compilador; la opción -api-version fija qué parte de la biblioteca estándar puedes usar. Poder bajar la segunda sin bajar la primera es lo que permite actualizar el compilador de una biblioteca sin obligar a sus consumidores a actualizar también.
kotlinc miapp.kt -language-version 2.4 -api-version 2.2 -d miapp.jar
Estabilidad y la ventana de dieciocho meses
Nada entra en Kotlin como definitivo desde el primer día. El escalón está declarado y aparece en la documentación de cada característica y de cada componente del ecosistema.
Experimental
Puede cambiar o desaparecer sin aviso y sin ruta de migración. Hay que activarla explícitamente. Sirve para recoger opiniones, no para producción.
Alfa
La idea se sostiene y se seguirá desarrollando, pero la forma final cambiará. Úsala solo si puedes reescribir el código afectado sin drama.
Beta
El diseño está congelado y solo faltan detalles. Hay compromiso explícito de proporcionar una ruta de migración cuando se estabilice.
Estable
Compatibilidad garantizada hacia atrás en el mismo primer número de versión. Cualquier retirada pasa antes por el ciclo completo de deprecación.
El uso de lo no estable exige consentimiento explícito mediante el mecanismo de exclusión voluntaria, de modo que ninguna dependencia pueda arrastrarte a una API inestable sin que quede registrado en tu código. Ese registro es la parte importante: convierte una decisión de riesgo en algo auditable con una búsqueda de texto.
@OptIn(ExperimentalStdlibApi::class)
fun usarAlgoNuevo() {
// el consentimiento queda escrito en el propio archivo
}
La deprecación funciona en fases y a lo largo de varias versiones de características: primero el compilador emite una advertencia y ofrece la alternativa, después la convierte en error, y solo mucho más tarde se elimina el símbolo. Ese ritmo es lento a propósito, porque el público de Kotlin incluye bases de código de millones de líneas que no pueden migrar en un trimestre. La anotación de deprecación puede además llevar la corrección automática, de modo que el IDE aplique la migración por ti.
@Deprecated(
message = "Usa formatearImporte, que respeta la configuración regional",
replaceWith = ReplaceWith("formatearImporte(valor)"),
level = DeprecationLevel.WARNING // después WARNING pasa a ERROR, y luego HIDDEN
)
fun formatear(valor: Long): String = formatearImporte(valor)
Merece la pena ver el ciclo completo con un ejemplo real de la rama 2.x. Las condiciones de guarda en when, que permiten añadir una condición extra a una rama sin anidar otro bloque, aparecieron en vista previa en la 2.1 y se estabilizaron en la 2.2. Entre una versión y otra hubo dos cosas: retroalimentación pública y un compromiso de que la sintaxis no cambiaría al estabilizarse.
when (respuesta) {
is Exito if respuesta.datos.isEmpty() -> mostrarVacio()
is Exito -> mostrar(respuesta.datos)
is Fallo -> reintentar()
}
La novedad de 2026 es la política formal de soporte de seguridad. Desde la 2.4, publicada en junio de 2026, cada versión de características recibe correcciones de seguridad durante dieciocho meses desde su lanzamiento. Eso convierte una decisión antes difusa en una planificación aritmética: si tu organización quiere permanecer siempre dentro de la ventana con dos versiones de características al año, tienes margen para saltarte una, pero no dos.
Aprende a leer un número de versión como se lee una cláusula contractual y dejarás de actualizar por superstición. Cuando Kotlin publica una 2.4, está afirmando tres cosas simultáneas: que tu código de 2.0 sigue compilando, que lo marcado como obsoleto en 2.2 puede haberse vuelto error, y que recibirás parches de seguridad hasta finales de 2027. Nada de eso es opinable, y todo se puede meter en una hoja de cálculo. La consecuencia práctica es que el debate habitual sobre si actualizar está mal planteado: la pregunta correcta no es si la versión nueva trae algo que te apetezca, sino en qué fecha exacta la tuya deja de recibir parches y cuántas versiones de características te separan de la última soportada. Esa disciplina es también la razón por la que K2 pudo desplegarse sin fracturar el ecosistema: JetBrains pasó tres años enseñando el compilador nuevo en alfa y beta, con la versión anterior disponible, antes de convertirlo en el predeterminado en la 2.0. Un cambio de esa profundidad solo se sobrevive si la política de estabilidad se ganó la confianza mucho antes de necesitarla.
- Averigua la versión exacta de Kotlin que usa tu proyecto actual y calcula, con la política de dieciocho meses, en qué fecha deja de recibir correcciones de seguridad.
- Compila un archivo pequeño fijando
-language-versiony-api-versiona valores distintos y provoca a propósito un error usando una API más nueva que la versión de API declarada. - Elige una característica del lenguaje que hoy sea estable y reconstruye en qué versión entró como experimental y cuántas versiones tardó en estabilizarse.
- Escribe un párrafo que explique a alguien de tu equipo por qué el salto de 1.9 a 2.0 fue distinto del salto de 1.8 a 1.9.
- Diseña la política de actualización de un equipo hipotético con dos versiones de características al año: cuándo se actualiza, quién lo valida y cuál es el margen máximo de retraso tolerable.