Kotlin 1.2-beta

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).