NOTA: Este artículo es una traducción manual de este otro artículo.

Versión preeliminar:

Esta es una versión preeliminar. Para poder utilizarla en maven o en gradle, tienes que incluir el repositorio de gradle http://dl.bintray.com/kotlin/kotlin-eap-1.2:

buildscript {
    ext.kotlin_version = '1.2-beta'

    repositories {
        maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.2" }
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
    

Nos complace anunciar la versión Kotlin 1.2 beta. Con esta versión, desvelamos la característica más relevante de Kotlin 1.2: soporte experimental para proyectos multiplataforma. También, consideramos ya completa la librería estándar y del lenguaje de la 1.2. Y ya hemos implementado todas las características planeadas para Kotlin 1.2. Ahora es el momento ideal para que nos déis vuestra opinión sobre los cambios - todavía tenemos tiempo para tener en cuenta vuestros comentarios y ajustar el diseño de la versión final de la 1.2 si es necesario.

En relación a las herramientas, la beta de Kotlin 1.2, incluye el mismo conjunto de características que se han liberado recientemente en la actualización 1.1.50. La beta es compatible con todas las versiones de IntelliJ IDEA desde la 2016.3 gasta la 2017.3, así como Android Studio 2.3 y 3.0.

La lista de cambios completa desde la 1.2-M2 se puede encontrar aquí, con las cosas más destacadas en la parte siguiente del artículo.

Proyectos multiplataforma

Los proyectos multiplataforma son una característica experimental en Kotlin 1.2, permitiendo reusar código entre plataformas destino soportadas por Kotlin - JVM, JavaScript y (en el futuro) Nativo. En un proyecto multiplataforma, pones código que se comparte entre plataformas en un módulo común, y las partes específicas de cada plataforma en módulos específicos de cada plataforma que dependen de él. Cuando compilas dichos proyectos para la plataforma específica, el código de ambos, el común y las partes específicas de plataforma, se genera.

Una característica clave del soporte de los proyectos multiplataforma es la posibilidad de expresar las dependencias de código común en partes específicas de plataforma a través de declaraciones expected y actual. Una declaración expected especifica un API (clase, interfaz, anotación, declaración global, etc.). Una declaración actual es o bien una implementación específica por plataforma del API o un alias de tipo (typealias) redireccionando a una implementación existente del API en una librería externa:

// Common code
expect fun hello(world: String)

expect class URL(spec: String) {
  open fun getHost(): String
  open fun getPath(): String
}

// JVM code
actual fun hello(world: String) {
  println("Hello JVM $world")
}

actual typealias URL = java.net.URL

Para más información, echad un vistazo a la documentación de los proyectos multiplataforma.

Si ya habéis probado esta característica antes de que se anunciase, por favor, tened en cuenta que tenéis que actualizar vuestros proyectos: los keywords header y impl se han renombrado a expect y actual. Para actualizar vuestro código automáticamente usad Analyze | Cleanup Code... en IntelliJ IDEA.

Lenguaje y compilador

Literales de array en anotaciones

Una nueva característica del lenguaje en Kotlin 1.2 es el soporte de literales de array en anotaciones. Ahora, en vez de escribir algo como @CacheConfig(cacheNames = arrayOf("books", "default")) podéis simplemente usar una expresión literal:

@CacheConfig(cacheNames = ["books", "default"])

Dicha característica ya estaba disponible en el hito anterior de Kotlin 1.2. En la beta 1.2, hemos hecho la sintaxis más consistente y permitimos usar los literales de array tanto en arrays como en parámetros vararg:

@RequestMapping(value = ["value1", "value2"], path = ["path1", "path2"])

Para habilitar dicho cambio, hemos decidido hacer ciertos ajustes a la sintaxis para usar argumentos con nombre junto a vararg, tanto en llamadas a métodos normales como en anotaciones. Puede que os sorprenda, pero en Kotlin 1.1, cuando llamábamos a métodos vararg usando la sintaxis de argumentos con nombre, era posible pasar un solo argumento como un valor inmediato:

fun foo(vararg strs: String) { ... }

foo(strs = "abc")

Decir que a strs se le pasa una cadena "abc" parece algo poco intuitivo, y también nos obliga a usar el operador de propagación cuando pasamos un array entero como un argumento con nombre:

foo(strs = *arr)

Nos encantaría permitir foo(strs = arr), pero por compatibilidad, requiere una migración progresiva, así que en la 1.2 hemos deprecado foo(strs = "abc") y como reemplazo (en el caso poco probable de que hayáis usado esta sintaxis), podéis usar el operador de propagación y el método arrayOf:

foo(x = *arrayOf("abc"))

Tenemos planeado implementar una optimización en el compilador para evitar la reserva del array y su correspondiente copia en dichas llamadas.

Como las anotaciones están en un ámbito mucho más restringido, nos podemos saltar un paso en la migración, asó que podéis usar los literales de array sin usar el operador de propagación:

annotation class Foo(vararg value: String)

@Foo(value = "a") // deprecated
@Foo(value = ["a"]) // correct

Echad un ojo a esta entrada en TouTrack para más información.

Mejoras en lateinit

Hemos añadido una nueva API de reflexión para permitir comprobar si una variable lateinit ha sido inicializada.

lateinit var file: File

// ...

if (::file.isInitialized) {
  ...
}

Esto es una implementación parcial de la propuesta de este KEEP; la parte restante (el método de desinicialización) se ha pospuesto, y posiblemente se implemente en la 1.3.

A partir de ahora también se puede usar el modificador lateinit tanto en declaraciones globales, como en variables locales. Donde la última se puede usar, por ejemplo, al inicializar un grafo de objetos en el que hay una dependencia circular entre las propiedades de los objetos y el grafo. Ejemplo:

fun test() {
  lateinit var x: Component

  // inject takes a lambda which must return the Component though
  val injector = inject(
    ...,
    componentProvider = { x },
    ...
  )

  // Initialization is only possible via injector, once it has been run
  x = injector.createComponent()
}

Echad un ojo al KEEP para obtener más información.

### Mejoras en las referencias llamables vinculadas Bound callable reference

Ahora podéis omitir this en las expresiones somo this::foo, para crear referencias llamables vinculadas. En su lugar, podéis escribir simplemente ::foo. Anteriormente la sintaxis con la parte izquierda vacía únicamente se podía usar para crear referencias llamables en declaraciones globales. Para más información, echado un ojo a esta entrada en YouTrack.

Mejoras de inferencia de tipos

Ahora el compilador de Kotlin puede usar la información del casteo de tipos para realizar la inferencia de tipos. Si llamáis a un método genérico que devuelve un parámetro de tipo T y casteais el valor de retorno a un tipo específico Foo, el compilador ahora entiende que T para esta llamada tiene que estar vinculada al tipo Foo. Esto es particularmente importante para los desarrolladores Android porque el compilador puede analizar correctamente las llamadas a findViewById en el nivel de API de android 26:

val button = findViewById(R.id.button) as Button

Como el método se ha cambiado a <T extends View> T findViewById(int id) en Kotlin 1.1 no se podía inferir el tipo del argumento T en dichas llamadas. Para más información, echad un ojo a esta entrada de YouTrack.

Advertencias como errores

El compilador ahora proporciona una opción para tratar todas las advertencias como errores. Usad -Werror en la línea de comandos, o el siguiente snippet de Gradle:

compileKotlin {
  kotlinOptions.warningsAsErrors = true
}

Mejoras en los smart cast

Los smart casts ahora se aplican a los sujetos de los casteos seguros:

fun foo(x: Foo?) {
  val b = (x as? SubClass)?.subclassMethod1()
  if (b != null) {
    x.subclassMethod2() // x is smart cast to SubClass
  }
}

Ahora también se permiten los smart casts en lambdas para variables var que se modifican únicamente antes de la lambda:

var x: String? = null
if (flag) x = "Yahoo!"

run {
  if (x != null) {
    println(x.length) // x is smart cast to String
  }
}

Clases anidadas en entradas de enum

Hemos deprecado las clases anidadas dentro de entradas de enums; y como corrección, debéis marcar las clases como inner.

Librería estándar

Compatibilidad con la separación de paquetes

La librería estándar de Kotlin es ahora completamente compatible con el sistema de módulos de Java 9, que prohibe separar paquetes (multiple archivos jar declarando clases en el mismo paquete). Para soportar eso, hemos creado nuevos artefactos kotlin-stdlib-jdk7 y kotlin-stdlib-jdk8, que reemplazan los viejos kotlin-stdlib-jre7 y kotlin-stdlib-jre8. Las declaraciones en el nuevo artefacto son visibles bajo los mismos nombres de paquete desde el punto de vista de Kotlin, pero, debido a cierta magia del compilador que hemos añadido, son visibles desde diferentes nombres de paquete desde Java. De forma que, cambiar a los nuevos artefactos no os supondrá ningún cambio en vuestro código.

Otro cambio que hemos hecho para cercionarnos de la compatibilidad con el nuevo sistema de módulos es quitar las declaraciones deprecadas del paquete kotlin.reflect de la librería kotlin-reflect. Si los estábais usando, tendréis que hacer el cambio a las declaraciones en el paquete kotlin.reflect.full, que está disponible desde Kotlin 1.1.

kotlin.math

kotlin.math es un nuevo paquete de la librería estándar de Kotlin 1.2, que permite realizar operaciones matemáticas en el código multiplataforma. En la 1.2-Beta, hemos hecho varias mejoras :

  • Incluimos las funciones hiperbólicas (asinh, acosh, atanh)
  • Hemos añadido las funciones relacionadas con la representación binaria de los números en coma flotante (toBits, nextUp y demás), también a JavaScript
  • Mejoras mejorado la precisión de los polyfills de matemáticas en JavaScript

Notas de versiones preeliminares

Como en otras versiones hito, no damos ningún tipo de garantía de compatibilidad para las características nuevas del lenguaje o de las librerías. Cualquier cosa introducida en las versiones preeliminares de la 1.2 está sujeta a cambio antes de la versión final de la 1.2. Cuando alcancemos la versión final, los binarios producidos por versiones preeliminares serán rechazadas por el compilador: lo que os obligará a recompilar todo lo que se había compilado en las 1.2‑Mx o 1.2-Beta. Sin embargo, todo el código compilado por las versiones 1.1.x o anteriores es perfectamente válido sin necesidad de recompilar.

Cómo probarlo

En Maven/Gradle: Añadid http://dl.bintray.com/kotlin/kotlin-eap-1.2 como repositorio en vuestros build script y vuestros proyectos; usad 1.2.0-beta-31 como número de versión para el plugin del compilador y la librería estándar.

En IntelliJ IDEA: Id a Tools → Kotlin → Configure Kotlin Plugin Updates, y seleccionad “Early Access Preview 1.2” en el desplegable de Update channel, y pulsad Check for updates. El compilador de la línea de comandos se puede descargar la página de release de GitHub.

En try.kotlinlang.org: Usad el desplegable de la esquina inferior derecha para cambiar el compilador a la versión 1.2‑Beta (próximamente).