{"id":121429,"date":"2021-03-04T23:29:23","date_gmt":"2021-03-04T22:29:23","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=kotlin&#038;p=121429"},"modified":"2021-03-04T23:29:23","modified_gmt":"2021-03-04T22:29:23","slug":"avance-de-las-nuevas-funcionalidades-de-lenguaje-en-kotlin-1-4-30","status":"publish","type":"kotlin","link":"https:\/\/blog.jetbrains.com\/es\/kotlin\/2021\/03\/avance-de-las-nuevas-funcionalidades-de-lenguaje-en-kotlin-1-4-30\/","title":{"rendered":"Avance de las nuevas funcionalidades de lenguaje en Kotlin 1.4.30"},"content":{"rendered":"<p>Planeamos a\u00f1adir nuevas funcionalidades de lenguaje en Kotlin 1.5, y ya puede probarlas en Kotlin 1.4.30:<\/p>\n<ul>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#inline-value-classes-stabilization\">Estabilizaci\u00f3n de clases inline value<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#jvm-records\">Compatibilidad experimental con registros JVM<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#sealed-interfaces\">Compatibilidad experimental con interfaces sealed y otras mejoras para clases sealed<\/a><\/li>\n<\/ul>\n<p>Para probar estas nuevas funcionalidades, tiene que <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#how-to-try\">especificar la versi\u00f3n de lenguaje 1.5<\/a>.<\/p>\n<p>La nueva <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2020\/10\/new-release-cadence-for-kotlin-and-the-intellij-kotlin-plugin\/\">cadencia de lanzamientos<\/a> significa que Kotlin 1.5 se publicar\u00e1 dentro de pocos meses, pero ya hay nuevas funcionalidades disponibles para probarlas en la versi\u00f3n 1.4.30. Sus comentarios iniciales son cruciales para nosotros, \u00a1as\u00ed que no dude en probar estas funcionalidades nuevas ya!<\/p>\n<p><a href=\"https:\/\/youtrack.jetbrains.com\/issues?q=tag:%20Language\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/02\/Kotlin-1.4.30-new-lang-features-banner_2-02.png\" alt=\"\" \/><\/a><\/p>\n<h2>Estabilizaci\u00f3n de clases inline value<\/h2>\n<p><a name = \"inline-value-classes-stabilization\"><\/a><\/p>\n<p><a href=\"https:\/\/kotlinlang.org\/docs\/reference\/inline-classes.html\" target=\"_blank\" rel=\"noopener\">Las clases inline<\/a> llevan disponibles en <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/evolution\/components-stability.html#stability-levels-explained\" target=\"_blank\" rel=\"noopener\">Alpha<\/a> desde Kotlin 1.3, y en la versi\u00f3n 1.4.30 avanzan a <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/evolution\/components-stability.html#stability-levels-explained\" target=\"_blank\" rel=\"noopener\">Beta<\/a>.<\/p>\n<p>Kotlin 1.5 estabiliza el concepto de clases inline, pero lo incluye como parte de una funcionalidad m\u00e1s general, las <em>clases value<\/em>, que describiremos m\u00e1s adelante en esta publicaci\u00f3n.<\/p>\n<p>Comenzaremos con un repaso del funcionamiento de las clases inline. Si ya est\u00e1 familiarizado con las clases inline, puede omitir esta secci\u00f3n e ir directamente a los <a href=\"#jvm-name-support\">nuevos cambios<\/a>.<\/p>\n<p>Como recordatorio r\u00e1pido, una clase inline elimina un contenedor alrededor de un valor:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\ninline class Color(val rgb: Int)\n<\/pre>\n<p>Una clase inline puede ser un contenedor tanto para un tipo primitivo como para cualquier tipo de referencia, como <code>String<\/code>.<\/p>\n<p>El compilador reemplaza las instancias de clase inline (en nuestro ejemplo, la instancia <code>Color<\/code>) con el tipo subyacente (<code>Int<\/code>) en el bytecode, cuando es posible:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\nfun changeBackground(color: Color) \nval blue = Color(255)\nchangeBackground(blue)\n<\/pre>\n<p>Entre bastidores, el compilador genera la funci\u00f3n <code>changeBackground<\/code> con un nombre alterado que usa <code>Int<\/code> como un par\u00e1metro, y transmite la constante <code>255<\/code> directamente sin crear un contenedor en el sitio de la llamada:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\nfun changeBackground-euwHqFQ(color: Int) \nchangeBackground-euwHqFQ(255) \/\/ no extra object is allocated! \n<\/pre>\n<p>El nombre se altera para permitir la sobrecarga continua de funciones que usan instancias de diferentes clases inline y para evitar invocaciones accidentales desde el c\u00f3digo Java que podr\u00eda infringir las restricciones internas de una clase inline. Lea <a href=\"#jvm-name-support\">a continuaci\u00f3n<\/a> para saber c\u00f3mo hacer que se pueda usar en Java.<\/p>\n<p>El contenedor no siempre se elimina en el bytecode. Esto ocurre solo cuando es posible, y funciona de manera muy similar a los tipos primitivos integrados. Cuando define una variable del tipo <code>Color<\/code> o la transmite directamente a una funci\u00f3n, se reemplaza con el valor subyacente:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\nval color = Color(0)        \/\/ primitive\nchangeBackground(color)     \/\/ primitive\n<\/pre>\n<p>En este ejemplo, la variable <code>color<\/code> tiene el tipo <code>Color<\/code> durante la compilaci\u00f3n, pero se reemplaza por <code>Int<\/code> en el bytecode.<\/p>\n<p>Sin embargo, si la almacena en una colecci\u00f3n o la transmite a una funci\u00f3n gen\u00e9rica, se se le aplica la conversi\u00f3n boxing en un objeto regular del tipo <code>Color<\/code>:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\ngenericFunc(color)         \/\/ boxed\nval list = listOf(color)   \/\/ boxed\nval first = list.first()   \/\/ unboxed back to primitive\n<\/pre>\n<p>El compilador aplica de forma autom\u00e1tica la conversi\u00f3n boxing y unboxing. No necesita hacer nada al respecto, pero resulta \u00fatil comprender el funcionamiento interno.<\/p>\n<h3>Cambio del nombre JVM para las llamadas Java<\/h3>\n<p><a name = \"jvm-name-support\"><\/a><\/p>\n<p>A partir de la versi\u00f3n 1.4.30, puede cambiar el nombre JVM de una funci\u00f3n que use una clase inline como par\u00e1metro para que sea utilizable en Java. De forma predeterminada, esos nombres se alteran para evitar utilizaciones accidentales de Java o sobrecargas conflictivas (como <code>changeBackground-euwHqFQ<\/code> en el ejemplo de arriba).<\/p>\n<p>Si anota una funci\u00f3n con <code>@JvmName<\/code>, cambia el nombre de esta funci\u00f3n en el bytecode y permite que se pueda llamar desde Java y transmitir un valor directamente:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ Kotlin declarations\ninline class Timeout(val millis: Long)\n\nval Int.millis get() = Timeout(this.toLong())\nval Int.seconds get() = Timeout(this * 1000L)\n\n@JvmName(&quot;greetAfterTimeoutMillis&quot;)\nfun greetAfterTimeout(timeout: Timeout)\n\n\/\/ Kotlin usage\ngreetAfterTimeout(2.seconds)\n\n\/\/ Java usage\ngreetAfterTimeoutMillis(2000);\n<\/pre>\n<p>Como siempre con una funci\u00f3n anotada con <code>@JvmName<\/code>, desde Kotlin la llama por su nombre de Kotlin. La utilizaci\u00f3n de Kotlin es segura para los tipos, ya que solo puede transmitir un valor del tipo <code>Timeout<\/code> como argumento, y las unidades son obvias por la utilizaci\u00f3n.<\/p>\n<p>En Java, puede transmitir un valor <code>long<\/code> directamente. Ya no es seguro para los tipos, y por eso no funciona de forma predeterminada. Si ve <code>greetAfterTimeout(2)<\/code> en el c\u00f3digo, no resulta obvio de inmediato si se refiere a 2 segundos, 2 milisegundos o 2 a\u00f1os.<\/p>\n<p>Al proporcionar la anotaci\u00f3n, <em>hace hincapi\u00e9<\/em> expl\u00edcitamente en que pretende que se llame a esta funci\u00f3n desde Java. Un nombre descriptivo le ayuda a evitar confusiones: si a\u00f1ade el sufijo \u00abMillis\u00bb al nombre JVM, las unidades ser\u00e1n claras para los usuarios de Java.<\/p>\n<h3>Bloques Init<\/h3>\n<p><a name = \"init-blocks\"><\/a><\/p>\n<p>Otra mejora para las clases inline en la versi\u00f3n 1.4.30 es que ahora puede definir la l\u00f3gica de inicializaci\u00f3n en el bloque <code>init<\/code>:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\ninline class Name(val s: String) {\n   init {\n       require(s.isNotEmpty())\n   }\n}\n<\/pre>\n<p>Esto estaba prohibido previamente.<\/p>\n<p>Puede consultar m\u00e1s detalles sobre las clases inline en <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/inline-classes.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a>, en la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#improved-inline-classes\" target=\"_blank\" rel=\"noopener\">documentaci\u00f3n<\/a> y en la conversaci\u00f3n debajo de <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42434\" target=\"_blank\" rel=\"noopener\">esta incidencia<\/a>.<\/p>\n<h3>Clases inline value<\/h3>\n<p><a name = \"inline-value-classes\"><\/a><\/p>\n<p>Kotlin 1.5 estabiliza el concepto de clases inline y lo convierte en parte de una funcionalidad m\u00e1s general: clases value.<\/p>\n<p>Hasta ahora, las clases \u00abinline\u00bb constitu\u00edan una funcionalidad de lenguaje independiente, pero ahora se est\u00e1n volviendo una optimizaci\u00f3n JVM espec\u00edfica para una clase value con un par\u00e1metro. Las clases value representan un concepto m\u00e1s general y admitir\u00e1n diferentes optimizaciones: las clases inline ahora, y las clases primitivas Valhalla en el futuro cuando el proyecto Valhalla est\u00e9 disponible (puede leer m\u00e1s informaci\u00f3n sobre esto <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#valhalla\">abajo<\/a>).<\/p>\n<p>Lo \u00fanico que cambia para usted en este momento es la sintaxis. Como una clase inline es un clase value optimizada, tiene que declararla de manera diferente a como lo hac\u00eda:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n@JvmInline\nvalue class Color(val rgb: Int)\n<\/pre>\n<p>Usted define una clase value con un par\u00e1metro de constructor y la anota con <code>@JvmInline<\/code>. Esperamos que todo el mundo utilice esta nueva sintaxis a partir de Kotlin 1.5. La sintaxis <code>inline class<\/code> anterior seguir\u00e1 funcionando durante un tiempo. Dejar\u00e1 de emplearse con una advertencia en la versi\u00f3n 1.5 que incluir\u00e1 la opci\u00f3n de migrar todas sus declaraciones de forma autom\u00e1tica. Posteriormente, quedar\u00e1 obsoleta y devolver\u00e1 un error.<\/p>\n<h2>Clases value<\/h2>\n<p><a name = \"value-classes\"><\/a><\/p>\n<p>Una clase <code>value<\/code> representa una entidad immutable con datos. Actualmente, una clase <code>value<\/code> puede contener <em>solo una<\/em> propiedad para admitir el caso de uso de las clases inline \u00abantiguas\u00bb.<\/p>\n<p>En futuras versiones de Kotlin con compatibilidad total con esta funcionalidad, ser\u00e1 posible definir clases value con muchas propiedades. Todos los valores deber\u00edan ser <code>val<\/code>s de solo lectura:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\nvalue class Point(val x: Int, val y: Int)\n<\/pre>\n<p>Las clases value no tienen identidad: est\u00e1n definidas completamente por los datos almacenados y no admiten las comprobaciones de identidad ===. La comprobaci\u00f3n de igualdad == compara de forma autom\u00e1tica los datos subyacentes.<\/p>\n<p>Esta calidad \u00absin identidad\u00bb de las clases value permiten futuras optimizaciones considerables: la llegada del proyecto Valhalla a JVM permitir\u00e1 la implementaci\u00f3n de las clases value como clases primitivas JVM entre bastidores.<\/p>\n<p>La restricci\u00f3n de inmutabilidad, y por ello la posibilidad de optimizaciones de Valhalla, hace que las clases <code>value<\/code> sean diferentes de las clases <code>data<\/code>.<\/p>\n<h3>Optimizaciones futuras de Valhalla<\/h3>\n<p><a name = \"valhalla\"><\/a><\/p>\n<p><a href=\"https:\/\/openjdk.java.net\/jeps\/8251554\" target=\"_blank\" rel=\"noopener\">El proyecto Valhalla<\/a> introduce un nuevo concepto para Java y JVM: las clases primitivas.<\/p>\n<p>El objetivo principal de las clases primitivas es combinar primitivas con rendimiento con las ventajas orientadas a objetos de las clases JVM habituales. Las clases primitivas son poseedoras de datos cuyas instancias se pueden almacenar en variables, en la pila de computaci\u00f3n, y operarse directamente, sin encabezados y pointers. A este respecto, son similares a los valores primitivos como <code>int<\/code>, <code>long<\/code>, etc. (en Kotlin, no trabaja con tipos primitivos directamente, sino que el compilador los genera entre bastidores).<\/p>\n<p>Una ventaja importante de las clases primitivas es que permiten la disposici\u00f3n plana y densa de objetos en la memoria. Actualmente, <code>Array&lt;Point&gt;<\/code> es un conjunto de referencias. Con la compatibilidad con Valhalla, al definir <code>Point<\/code> como una clase primitiva (en terminolog\u00eda Java) o como una clase value con la optimizaci\u00f3n subyacente (en terminolog\u00eda Kotlin), JVM puede optimizarlo y almacenar un conjunto de <code>Point<\/code>s en una distribuci\u00f3n \u00abplana\u00bb, como un conjunto de muchas <code>x<\/code>s e <code>y<\/code>s directamente, no como un conjunto de referencias.<\/p>\n<p>Estamos deseando que lleguen los pr\u00f3ximos cambios en JVM y queremos que Kotlin los aproveche. Al mismo tiempo, no queremos obligar a nuestra comunidad a depender de las nuevas versiones de JVM para usar las clases <code>value<\/code>, por lo que vamos a admitirlas tambi\u00e9n para las versiones de JVM anteriores. Al compilar el c\u00f3digo para JVM con compatibilidad con Valhalla, las optimizaciones JVM m\u00e1s recientes funcionar\u00e1n para las clases value.<\/p>\n<h3>M\u00e9todos mutantes<\/h3>\n<p><a name = \"mutating-methods\"><\/a><\/p>\n<p>Hay mucho m\u00e1s que decir sobre la funcionalidad de las clases value. Como las clases value representan datos \u00abinmutables\u00bb, los m\u00e9todos mutantes, como los de <a href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/Methods.html\" target=\"_blank\" rel=\"noopener\">Swift<\/a>, son posibles para ellos. Un m\u00e9todo mutante es cuando una funci\u00f3n de miembro o setter de propiedad devuelve una nueva instancia en lugar de actualizar una existente, y la ventaja principal es que usted lo utiliza con una sintaxis familiar. Esto a\u00fan tiene que hacerse prototipo en el lenguaje.<\/p>\n<h3>M\u00e1s detalles<\/h3>\n<p><a name = \"read-more-value-classes\"><\/a><\/p>\n<p>La anotaci\u00f3n <code>@JvmInline<\/code> es espec\u00edfica de JVM. En otros backends, las clases value pueden implementarse de manera diferente. Por ejemplo, como structs Swift en Kotlin\/Native.<\/p>\n<p>Puede leer los detalles sobre las clases value en <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/notes\/value-classes.md\" target=\"_blank\" rel=\"noopener\">Design Notes on Kotlin Value Classes<\/a>, o ver un extracto de la charla <a href=\"https:\/\/www.youtube.com\/watch?v=0FF19HJDqMo&amp;t=26m32s\" target=\"_blank\" rel=\"noopener\">\u00abA look into the future\u00bb<\/a> de Roman Elizarov.<\/p>\n<h2>Compatibilidad con los registros JVM<\/h2>\n<p><a name = \"jvm-records\"><\/a><\/p>\n<p>Otra mejora pr\u00f3xima en el ecosistema JVM son los <a href=\"https:\/\/openjdk.java.net\/jeps\/395\" target=\"_blank\" rel=\"noopener\">registros Java<\/a>. Son an\u00e1logos a las clases <code>data<\/code> de Kotlin y son, b\u00e1sicamente, titulares de los datos.<\/p>\n<p>Los registros Java no siguen la convenci\u00f3n de JavaBeans, y tienen m\u00e9todos <code>x()<\/code> and <code>y()<\/code>  en lugar de los habituales  <code>getX()<\/code> and <code>getY()<\/code>.<\/p>\n<p>La interoperabilidad con Java siempre ha sido y ser\u00e1 una prioridad para Kotlin. Por ello, el c\u00f3digo de Kotlin \u00abcomprende\u00bb los nuevos registros Java y los ve como clases con propiedades de Kotlin. Esto funciona como lo hace para las clases Java regulares siguiendo la convenci\u00f3n JavaBeans:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ Java\nrecord Point(int x, int y) { }\n\/\/ Kotlin\nfun foo(point: Point) {\n    point.x \/\/ seen as property\n    point.x() \/\/ also works\n}\n<\/pre>\n<p>Principalmente por motivos de interoperabilidad, puede anotar su clase <code>data<\/code> con <code>@JvmRecord<\/code> para generar nuevos m\u00e9todos de registro JVM:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n@JvmRecord\ndata class Point(val x: Int, val y: Int)\n<\/pre>\n<p>La anotaci\u00f3n <code>@JvmRecord<\/code> hace que el compilador genere m\u00e9todos <code>x()<\/code> y <code>y()<\/code> en lugar de los m\u00e9todos est\u00e1ndar <code>getX()<\/code> y <code>getY()<\/code>. Asumimos que solo necesita utilizar esta anotaci\u00f3n para preservar la API de la clase al convertirla de Java a Kotlin. En el resto de casos de uso, las clases <code>data<\/code> familiares de Kotlin se pueden utilizar sin problema.<\/p>\n<p>Esta anotaci\u00f3n solo est\u00e1 disponible si compila c\u00f3digo Kotlin para la versi\u00f3n 15+ de JVM. Puede consultar m\u00e1s detalles sobre esta funcionalidad en <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/jvm-records.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a> o en la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#jvm-records-support\" target=\"_blank\" rel=\"noopener\">documentaci\u00f3n<\/a>, as\u00ed como en la conversaci\u00f3n de <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42430\" target=\"_blank\" rel=\"noopener\">esta incidencia<\/a>.<\/p>\n<h2>Mejoras en interfaces sealed y clases sealed<\/h2>\n<p><a name = \"sealed-interfaces\"><\/a><\/p>\n<p>Cuando hace una clase sealed, restringe la jerarqu\u00eda para definir subclases, lo que permite comprobaciones exhaustivas en las ramas <code>when<\/code>. En Kotlin 1.4, la jerarqu\u00eda de clase sealed incluye dos restricciones. En primer lugar, la clase superior no puede ser una interfaz sealed, sino una clase. En segundo lugar, todas las subclases deber\u00edan estar localizadas en el mismo archivo.<\/p>\n<p>Kotlin 1.5 elimina las dos restricciones: ahora puede hacer una <em>interfaz<\/em> sealed. Las subclases (tanto para clases sealed e interfaces sealed) deber\u00edan estar ubicadas en la misma unidad de compilaci\u00f3n y en el mismo paquete que la clase superior, pero ahora pueden localizarse en <em>diferentes<\/em> archivos.<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\nsealed interface Expr\ndata class Const(val number: Double) : Expr\ndata class Sum(val e1: Expr, val e2: Expr) : Expr\nobject NotANumber : Expr\n\nfun eval(expr: Expr): Double = when(expr) {\n    is Const -&gt; expr.number\n    is Sum -&gt; eval(expr.e1) + eval(expr.e2)\n    NotANumber -&gt; Double.NaN\n}\n<\/pre>\n<p>Las clases sealed, y ahora las interfaces, son \u00fatiles para definir jerarqu\u00edas de tipo de datos abstractos (ADT).<\/p>\n<p>Otro caso de uso importante que ahora se puede abordar bien con interfaces selladas es cerrar una interfaz para herencia e implementaci\u00f3n fuera de la biblioteca. Definir una interfaz como sealed restringe su implementaci\u00f3n a la misma unidad de compilaci\u00f3n y el mismo paquete, lo que en el caso de una biblioteca impide la implementaci\u00f3n fuera de la biblioteca.<\/p>\n<p>Por ejemplo, la interfaz <code>Job<\/code> del paquete <code>kotlinx.coroutines<\/code> solo est\u00e1 destinado a implementarse dentro de la biblioteca <code>kotlinx.coroutines<\/code>. Al hacerla sellada con <code>sealed<\/code> se explicita esta intenci\u00f3n:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\npackage kotlinx.coroutines\nsealed interface Job { ... }\n<\/pre>\n<p>Como usuario de la biblioteca, usted ya no tiene permiso para definir su propia subclase de <code>Job<\/code>. Esto siempre estaba \u00abimpl\u00edcito\u00bb, pero con las interfaces sealed, el compilador puede prohibirlo oficialmente.<\/p>\n<h3>Utilizar la compatibilidad con JVM en el futuro<\/h3>\n<p><a name = \"new-sealed-jvm-support\"><\/a><\/p>\n<p>La compatibilidad de avance de las clases sealed se ha introducido en Java 15 y en JVM. En el futuro, vamos a utilizar la compatibilidad natural con JVM para las clases sealed si compila c\u00f3digo Kotlin para el JVM m\u00e1s reciente (probablemente JVM 17 o posterior cuando esta funcionalidad sea estable).<\/p>\n<p>En Java, usted enumera expl\u00edcitamente todas las subclases de la clase o interfaz sealed en cuesti\u00f3n:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ Java\npublic sealed interface Expression\n    permits Const, Sum, NotANumber { ... }\n<\/pre>\n<p>Esta informaci\u00f3n se almacena en el archivo de clase con el nuevo atributo <code>PermittedSubclasses<\/code>. JVM reconoce las clases sealed en el tiempo de ejecuci\u00f3n y evita su extensi\u00f3n por subclases no autorizadas.<\/p>\n<p>En el futuro, cuando compile Kotlin al nuevo JVM, se utilizar\u00e1 esta nueva compatibilidad con JVM de las clases sealed. Entre bastidores, el compilador generar\u00e1 una lista de subclases permitidas en el bytecode para garantizar que haya compatibilidad con JVM y comprobaciones adicionales del tiempo de ejecuci\u00f3n.<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ for JVM 17 or later\nExpr::class.java.permittedSubclasses \/\/ [Const, Sum, NotANumber]\n<\/pre>\n<p>En Kotlin, no necesita especificar la lista de subclases. El compilador generar\u00e1 la lista sobre la base de las subclases declaradas en el mismo paquete.<\/p>\n<p>La habilidad para especificar expl\u00edcitamente las subclases para una clase superior o interfaz podr\u00eda a\u00f1adirse m\u00e1s adelante como una especificaci\u00f3n opcional. Actualmente, sospechamos que no ser\u00e1 necesario, pero estaremos encantados de conocer sus casos de uso y si necesita esta funcionalidad.<\/p>\n<p>Tenga en cuenta que, para las versiones JVM m\u00e1s antiguas, es te\u00f3ricamente posible definir una subclase Java para la interfaz sealed de Kotlin, pero \u00a1no lo haga! Dado que la compatibilidad de JVM con las subclases permitidas a\u00fan no est\u00e1 disponible, esta restricci\u00f3n solo la aplica el compilador de Kotlin. A\u00f1adiremos avisos del IDE para evitar que eso ocurra accidentalmente. En el futuro, el nuevo mecanismo se utilizar\u00e1 para las versiones JVM m\u00e1s recientes para garantizar que no haya subclases \u00abno autorizadas\u00bb de Java.<\/p>\n<p>Puede consultar m\u00e1s informaci\u00f3n sobre las interfaces sealed y las restricciones de clases sealed sueltas en <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/sealed-interface-freedom.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a> o en la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#sealed-interfaces\" target=\"_blank\" rel=\"noopener\">documentaci\u00f3n<\/a>, y ver la conversaci\u00f3n de <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42433\" target=\"_blank\" rel=\"noopener\">esta incidencia<\/a>.<\/p>\n<h2>C\u00f3mo probar las nuevas funcionalidades<\/h2>\n<p><a name = \"how-to-try\"><\/a><\/p>\n<p>Necesita utilizar Kotlin 1.4.30. Especifique la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/compiler-reference.html#-language-version-version\" target=\"_blank\" rel=\"noopener\">versi\u00f3n<\/a> de lenguaje 1.5 para habilitar las nuevas funcionalidades:<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\ncompileKotlin {\n    kotlinOptions {\n        languageVersion = &quot;1.5&quot;\n        apiVersion = &quot;1.5&quot;\n    }\n}\n<\/pre>\n<p>Para probar los registros JVM, tambi\u00e9n necesita utilizar jvmTarget 15 y habilitar las funcionalidades de avance de JVM: a\u00f1ada las opciones de compilador <code>-language-version 1.5<\/code> y <code>-Xjvm-enable-preview<\/code>.<\/p>\n<h3>Notas previas al lanzamiento<\/h3>\n<p>Tenga en cuenta que la compatibilidad con las nuevas funcionalidades es experimental y la compatibilidad con la versi\u00f3n de lenguaje 1.5 est\u00e1 en estado previo al lanzamiento. Configurar la versi\u00f3n de lenguaje a 1.5 en el compilador Kotlin 1.4.30 es equivalente a probar el avance 1.5-M0. Las garant\u00edas de compatibilidad con versiones anteriores no cubren las versiones previas al lanzamiento. Las funcionalidades y la API pueden cambiar en lanzamientos posteriores. Cuando llegamos a un Kotlin 1.5-RC final, el compilador expulsar\u00e1 todos los binarios producidos por las versiones previas al lanzamiento y se le pedir\u00e1 que vuelva a compilar todo lo que compil\u00f3 con la 1.5\u2011Mx.<\/p>\n<h3>Env\u00edenos sus comentarios<\/h3>\n<p>\u00a1Pruebe las nuevas funcionalidades descritas en esta publicaci\u00f3n y comparta su opini\u00f3n! Puede obtener m\u00e1s informaci\u00f3n en KEEPs y participar en las conversaciones en YouTrack, y puede informar de nuevas incidencias si algo no le funciona correctamente. \u00a1Comparta sus resultados sobre el \u00e9xito de las nuevas funcionalidades para abordar los casos de uso de sus proyectos!<\/p>\n<p>M\u00e1s informaci\u00f3n y debates:<\/p>\n<ul>\n<li><a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html\" target=\"_blank\" rel=\"noopener\">P\u00e1gina de documentaci\u00f3n \u00abNovedades\u00bb<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/inline-classes.md\" target=\"_blank\" rel=\"noopener\">Clases inline KEEP<\/a>; debate: <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42434\" target=\"_blank\" rel=\"noopener\">KT-42434<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/notes\/value-classes.md\" target=\"_blank\" rel=\"noopener\">Documento de dise\u00f1o de clases value<\/a>; debate en <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/issues\/237\" target=\"_blank\" rel=\"noopener\">KEEP<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/jvm-records.md\" target=\"_blank\" rel=\"noopener\">Registros JVM KEEP<\/a>; debate: <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42430\" target=\"_blank\" rel=\"noopener\">KT-42430<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/sealed-interface-freedom.md\" target=\"_blank\" rel=\"noopener\">Interfaces sealed y clases sealed KEEP<\/a>; debate: <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42433\" target=\"_blank\" rel=\"noopener\">KT-42433<\/a>.<\/li>\n<\/ul>\n","protected":false},"author":1086,"featured_media":113702,"comment_status":"closed","ping_status":"closed","template":"","categories":[907],"tags":[91,477],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/121429"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/types\/kotlin"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/users\/1086"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/comments?post=121429"}],"version-history":[{"count":1,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/121429\/revisions"}],"predecessor-version":[{"id":121430,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/121429\/revisions\/121430"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media\/113702"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media?parent=121429"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/categories?post=121429"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/tags?post=121429"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/cross-post-tag?post=121429"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}