Nuevo Kotlin User Group en Valencia y event "Estado de Machine Learning en Kotlin"
¡Se acaba de inaugurar el nuevo Kotlin Valencia User Group! Inicialmente organizado por Carlos Cáceres
Este post es una traducción de su artículo original en inglés.
Tras un largo verano, el equipo de Kotlin, tiene un montón de novedades sobre la M13:
<code class="highlighter-rouge">lateinit
para soportar inyección de dependencias y otras frameworks<code class="highlighter-rouge">sealed
para expresar jerarquías cerradas<code class="highlighter-rouge">@NotNull
(ver este post en inglés blog post)<code class="highlighter-rouge">internal
fuera de un módulo (más detalles abajo)<code class="highlighter-rouge">.class
para las funciones y propiedades libresEstamos terminando de completar el lenguaje y haciendo los cambios necesarios para finalizar la sintaxis así como añadiendo pequeñas cosas que todavía faltan para casos de uso críticos. Algunos de esos cambios implican romper algo de código, y como de costumbre os ayudamos en todo lo posible con la migración.
Nótese que con la versión 1.0 hacia la que estamos enfocados, se centrará en el soporte con la JVM. Se incluirá el backend de JavaScript, pero se considerará como experimental. Debido a eso, hay algunos cambios que afectan a JavaScript en esta release. Tenemos intención de retomar el trabajo con JS tras la 1.0.
Uno de los mayores problemas de usar Kotlin con frameworks que inyectan valores en campos Java (por ejemplo: inyección de dependencias, mocking, serialización y otros frameworks) solía ser la imposibilidad de tener una propiedad de un tipo no-nulo que no se inicializaba en el constructor.
Con la M13, introducimos propiedades <code class="highlighter-rouge">lateinit
.
class Example { @Inject lateinit val foo: Foo @Inject lateinit var bar: Bar }
Tanto foo como bar no están inicializados, pero también se declaran como tipos no nulos. Si tratamos de leerlos antes de que se inicialicen, se lanzará una excepción, pero en cuanto se inicialicen mediante el framework de inyección de dependencias (Guice, Dagger o Spring, por ejemplo), se pueden leer como propiedades normales.
Dichas propiedades también se pueden usar para otros casos de uso (como la inicialización setUp de JUnit). Nótese que tanto los <code class="highlighter-rouge">val
’s como los <code class="highlighter-rouge">var
’s se pueden marcar como <code class="highlighter-rouge">lateinit
. No se pueden asignar libremente por código, pero un framework puede inyectar valores en ellos sin ningún impedimento, porque los campos correspondientes de la JVM no son marcados como <code class="highlighter-rouge">final
.
Más información en la documentación del lenguaje.
Clases selladas (Sealed classes) Mucha gente pregunta si Kotlin soporta tipos de datos algebraicos (Algebraic Data Types (ADTs)). La respuesta siempre ha sido “Sí, los ADT se pueden expresar como clases en Kotlin, y when es prácticamente tan bueno como el pattern matching”. Ahora hemos añadido más seguridad tipada a dichos tipos: con las clases selladas podemos asegurarnos de que se contemplan todos los casos en los when.
package pets import pets.Pet.* sealed class Pet(val name: String) { class Dog(name: String): Pet(name) class Cat(name: String): Pet(name) } fun Pet.saySomething(): String { return when (this) { is Dog -> "woof" is Cat -> "meow" } }
Nótese que en el ejemplo no se quiere un else en el when. Debido a que Pet es una clase sellada, el compilador sabe que no hay más subclases además de Dog y Cat. Así que puede garantizar de que todos los casos se han comprobado y no se requiere de un else. Por ello, si olvidas cubrir algún caso, el compilador informará con un error y te recordará que debes hacerlo o añadir un else.
Por el momento, únicamente las clases anidadas dentro de la clase sellada pueden extenderla, pero posteriormente relajaremos esta restricción y permitiremos subclases dentro del mismo archivo.
Para más información, consulta la documentación.
En la M13 se han separado sintácticamente los modificadores y las anotaciones (más información en este post en inglés). Ahora requerimos @ para todas las anotaciones. Y se espera que todas las clases de las anotaciones empiecen por mayúscula (que permite una mayor uniformidad con Java).
Por ello, se ha renombrado anotaciones como @Throws o @Volatile. También hemos renombrado @platformName a @JvmName y @platformStatic a @JvmStatic.
Y estas anotaciones han pasado a ser modificadores:
<code class="highlighter-rouge">@inlineOption(ONLY_LOCAL_RETURNS)
Este cambio es transparente para la mayor parte de los usuarios para los casos en que los modificadores hayan mantenido su antiguo nombre.
La antigua sintaxis y las clases se han deprecado,
La acción de limpieza del IDE (Code Cleanup) os ayudará a mirar el código.
Kotlin ahora soporta las siguientes opciones para anotaciones (expresadas como anotaciones en las annotation classes):
<code class="highlighter-rouge">@Retention
– quién puede ver esta anotación: RUNTIME (valor por defecto), BINARY (solo en los archivos .class) o SOURCE<code class="highlighter-rouge">@Target
– dónde es aplicable la anotación<code class="highlighter-rouge">@MustBeDocumented
– indica que esta anotación es parte del API del elemento anotado, y por lo tanto se debe mostrar en la documentación generada<code class="highlighter-rouge">@Repeatable
– indica que la anotación se puede usar varias veces en un mismo elementoMás información en la documentación.
Adicionalmente, ahora podemos especificar un target opcional para la anotación:
class Example( @field:MyFieldAnnotation(...) val foo: Foo )
NOTA: este cambio puede romper código. Antes de la M13 cuando anotábamos parámetros del constructor primario, las anotaciones se aplicaban tanto a los parámetros como a los campos en los que se almacenaban. Ahora solo se guardan para el primero aplicable: parámetro, propiedad o campo. Esto presenta algunos problemas cuando se usa Jackson. Pero hay una forma fácil de arreglarlo: usar el módulo especial de Jackson para Kotlin.
Más información en la documentación.
Hemos reformado nuestro modelo de visibilidad. A partir de ahora:
<code class="highlighter-rouge">private
en propiedades y funciones libres significa “visible únicamente desde este archivo”<code class="highlighter-rouge">internal
a <code class="highlighter-rouge">public
In bases de código Java rales (donde las decisiones sobre public/private son explícitas), public ocurre mucho más amenudo que private (de 2.5 a 5 veces más a menudo en las bases de código que hemos examinado, incluyendo el compilador Kotlin y IntelliJ IDEA). Esto significa que haríamos escribir public por todas partes y que haría que Kotlin fuese mucho más ceremonial, y perderíamos parte del precioso terreno que hemos ganado a Java en cuando a la brevedad. Y nuestra propia experiencia nos dice que el public explícito rompe el flujo de muchos SDLs muy a menudo. Así que por todo eso hemos decidido mantenerlo como nuestro por defecto para mantener nuestro código limpio.
NOTA: <code class="highlighter-rouge">internal
se sigue soportando, pero ahora se debe explicitar.
<code class="highlighter-rouge">::foo
aunque <code class="highlighter-rouge">foo
esté sobrecargado, y la firma adecuada se elegirá en función del contexto<code class="highlighter-rouge">@HiddenDeclaration
para ocultar declaraciones a clientes manteniéndolos en los binarios (también para evolucionar APIs con mayor facilidad)La gente llevaba mucho tiempo pidiendo esta característica, y nos ha llevado algún tiempo ver cómo plantearla bien. Ahora al usar clases Java que definen propiedades por convención (ejemplo: getFoo() y opcionalmente setFoo()), Kotlin define automáticamente propiedades de extensión:
// Java: class JBean { public Foo getFoo() { return ...; } public void setFoo(Foo foo) { ... } } // Kotlin fun demo(bean: JBean) { println(bean.foo) // 'foo' is automatically defined }
Acceder a dichas propiedades está optimizado, así que bean.foo se compila a bean.getFoo() sin ninguna llamada intermedia.
Hace algunos meses anunciamos este cambio y ahora ya está hecho:
<code class="highlighter-rouge">MyFileKt
<code class="highlighter-rouge">@file:JvmName("CustomName")
en un archivo de código para cambiar el nombre de la clase generadaPara hacer que este cambio funcione, hemos tenido que introducir un nuevo archivo de recurso que se requiere para compilar código Kotlin contra binarios de Kotlin. Se llama<code class="highlighter-rouge">META-INF/<module_name>.kotlin_module
. **Aseguramos de que esos archivos .kotlin_module **no se descarten en vuestro proceso de empaquetado. También, aseguraos de que los nombres de módulo no colisionen en vuestro proyecto.
en Maven usamos el groupId y artifactId para los nombres de módulo, pero podéis utilizar
Es el nombre del proyecto + la tarea de construcción, y para personalizar:
compileKotlin { kotlinOptions.moduleName = "com.example.mymodule" }
Debes especificar los módulos explícitamente:
Más información aquí.
Anunciamos esto hace algún tiempo. Ahora podemos usar @NotNull y @Nullable en Java y Kotlin los reconoce de forma que un uso incorrecto emite errores en vez de warnings.
Como consecuencia, usar las colecciones de Java se ha vuelto mucho más seguro: ya no podemos poner un null en un <code class="highlighter-rouge">ArrayList<String>
.
Los tipos de plataforma se mantienen en su sitio, porque las anotaciones faltan a menudo o a veces son incorrectas (violando reglas de herencia, por ejemplo), así que por defecto no se imponen null-checks estáticos en código Java.
También hemos estado desarrollando activamente librerías de Kotlin. La M13 trae por fin una librería de reflexión completamente funcional: ya podemos introspeccionar clases, sus miembros, parámetros, etc. Habrá un post en el blog sobre esto próximamente.
La librería estándar ha recibido varias adiciones convenientes incluyendo:
Más sobre esto en otro post.
Demonio de compilación. Anunciamos el soporte para el demonio de Gradle hace algún tiempo y vuestro feedback ha sido positivo: los tiempos de compilación parecen haber bajado en un factor de tres. Seguimos trabajando en el rendimiento de compilación, y desde la M13 se utiliza un demonio similar al de gradle en IntelliJ IDEA también. Esta característica está marcada como “experimental” por el momento, así que tienes que activar checkbox en el diálogo de preferencias para activarlo:
Build, execution, deployment -> Compiler -> Kotlin compiler -> Keep compiler process alive between invocations (experimental)
La compilación incremental es otra dirección que estamos tomando para mejorar los tiempos de compilación de Kotlin. M13 trae:
Hemos mejorado también la experiencia del IDE. Para no extendernos demasiado, hemos destacado solo algunas de las características que no son tan fáciles de descubrir:
(En el post original podéis ver los gifs animados)
En IntelliJ IDEA 14.1 simplemente actualiza el plugin a través del gestor de plugins (como de costumbre).
En IntelliJ IDEA 15 EAP tiene Kotlin M12 integrado, así que para actualizar a M13 tienes que
Mejoraremos el proceso en las siguiente EAPs de IntelliJ IDEA.
Y como de costumbre, el compilador standalone se puede encontrar aquí.
¡Que tengáis un buen Kotlin!