{"id":127158,"date":"2021-02-23T16:53:25","date_gmt":"2021-02-23T15:53:25","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=kotlin&#038;p=127158"},"modified":"2021-03-23T16:57:06","modified_gmt":"2021-03-23T15:57:06","slug":"presentation-des-nouvelles-fonctionnalites-de-langage-dans-kotlin-1-4-30-2-fr","status":"publish","type":"kotlin","link":"https:\/\/blog.jetbrains.com\/fr\/kotlin\/2021\/02\/presentation-des-nouvelles-fonctionnalites-de-langage-dans-kotlin-1-4-30-2-fr\/","title":{"rendered":"Pr\u00e9sentation des nouvelles fonctionnalit\u00e9s de langage dans Kotlin 1.4.30"},"content":{"rendered":"<p>Voici les nouvelles fonctionnalit\u00e9s de langage que nous pr\u00e9voyons d\u2019ajouter dans Kotlin 1.5 et que vous pouvez d&#8217;ores et d\u00e9j\u00e0 essayer dans 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\">Stabilisation des classes de valeurs inline<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#jvm-records\">Prise en charge exp\u00e9rimentale des enregistrements de la 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\">Prise en charge exp\u00e9rimentale des interfaces scell\u00e9es et autres am\u00e9liorations pour les classes scell\u00e9es<\/a><\/li>\n<\/ul>\n<p>Pour essayer ces nouvelles fonctionnalit\u00e9s, vous devez <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#how-to-try\">sp\u00e9cifier la version 1.5 du langage<\/a> explicitement dans le code.<\/p>\n<p>La nouvelle <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2020\/10\/new-release-cadence-for-kotlin-and-the-intellij-kotlin-plugin\/\">cadence de publication<\/a> implique que Kotlin 1.5 ne sera disponible que dans quelques mois, mais de nouvelles fonctionnalit\u00e9s sont d\u00e9j\u00e0 disponibles en avant-premi\u00e8re dans la version 1.4.30. Il est important pour nous de recevoir vos retours d&#8217;exp\u00e9rience au plus t\u00f4t, alors n&#8217;h\u00e9sitez pas \u00e0 essayer ces nouvelles fonctionnalit\u00e9s d\u00e8s maintenant !<\/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>Stabilisation des classes de valeurs inline<\/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\">Les classes inline<\/a> sont disponibles en <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/evolution\/components-stability.html#stability-levels-explained\" target=\"_blank\" rel=\"noopener\">alpha<\/a> depuis Kotlin 1.3 et passent en <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/evolution\/components-stability.html#stability-levels-explained\" target=\"_blank\" rel=\"noopener\">b\u00eata<\/a>dans la version 1.4.30.<\/p>\n<p>Kotlin 1.5 stabilise le concept de classes inline mais l\u2019int\u00e8gre \u00e0 une fonctionnalit\u00e9 plus g\u00e9n\u00e9rale, les <em>classes de valeurs<\/em>, que nous d\u00e9crirons plus loin dans ce post.<\/p>\n<p>Commen\u00e7ons par rappeler le fonctionnement des classes inline. Si vous connaissez d\u00e9j\u00e0 les classes inline, vous pouvez passer cette section et consulter directement les <a href=\"#jvm-name-support\">derni\u00e8res modifications<\/a>.<\/p>\n<p>Pour rappel, une classe inline \u00e9limine une enveloppe (wrapper) autour d\u2019une valeur :<\/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>Une classe inline peut \u00eatre une enveloppe \u00e0 la fois pour un type primitif et pour tout type de r\u00e9f\u00e9rence, comme <code>String<\/code>.<\/p>\n<p>Le compilateur remplace les instances de classe inline (dans notre exemple, l\u2019instance <code>Color<\/code>) par le type sous-jacent (<code>Int<\/code>) dans le bytecode, lorsque c&#8217;est possible :<\/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>En coulisse, le compilateur g\u00e9n\u00e8re la fonction <code>changeBackground<\/code> avec un nom modifi\u00e9 prenant un param\u00e8tre <code>Int<\/code> et envoie directement la constante <code>255<\/code> sans cr\u00e9er d&#8217;enveloppe au point de l\u2019appel :<\/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>Le nom est alt\u00e9r\u00e9 afin de permettre que la surcharge des fonctions prenant des instances de plusieurs classes inline se fasse de fa\u00e7on fluide et d&#8217;emp\u00eacher les appels accidentels du code Java qui pourraient violer les contraintes internes d\u2019une classe inline. Poursuivez votre lecture <a href=\"#jvm-name-support\">ci-dessous<\/a> pour savoir comment la rendre utilisable \u00e0 partir de Java.<\/p>\n<p>L&#8217;enveloppe (wrapper) n\u2019est pas toujours \u00e9limin\u00e9e dans le bytecode. Cela n\u2019arrive que lorsque c\u2019est possible et fonctionne de mani\u00e8re tr\u00e8s similaire aux types primitifs int\u00e9gr\u00e9s. Lorsque vous d\u00e9finissez une variable du type <code>Color<\/code> ou que vous la passez directement dans une fonction, elle est remplac\u00e9e par la valeur sous-jacente :<\/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>Dans cet exemple, la variable <code>color<\/code> a le type <code>Color<\/code> lors de la compilation, mais elle est remplac\u00e9e par <code>Int<\/code> dans le bytecode.<\/p>\n<p>En revanche, si vous la stockez dans une collection ou si vous la passez dans une fonction g\u00e9n\u00e9rique, elle est encapsul\u00e9e (boxing) dans un objet ordinaire du type <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)   \/\/ boxied\nval first = list.first()   \/\/ unboxed back to primitive\n<\/pre>\n<p>La conversion boxing et unboxing est effectu\u00e9e automatiquement par le compilateur. Vous n\u2019avez rien \u00e0 faire, mais il est utile d&#8217;en comprendre le fonctionnement.<\/p>\n<h3>Changement du nom de la JVM pour les appels Java<\/h3>\n<p><a name = \"jvm-name-support\"><\/a><\/p>\n<p>\u00c0 partir de la version 1.4.30, vous pouvez changer le nom JVM d\u2019une fonction prenant une classe inline comme param\u00e8tre pour la rendre utilisable depuis Java. Par d\u00e9faut, ces noms sont modifi\u00e9s pour \u00e9viter les utilisations accidentelles de Java ou les surcharges conflictuelles (comme <code>changeBackground-euwHqFQ<\/code> dans l\u2019exemple ci-dessus).<\/p>\n<p>Si vous annotez une fonction avec <code>@JvmName<\/code>, cela change le nom de cette fonction dans le bytecode et permet de l\u2019appeler depuis Java et d&#8217;envoyer directement une valeur :<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ d\u00e9clarations Kotlin\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\/\/ utilisation Kotlin\ngreetAfterTimeout(2.seconds)\n\n\/\/ utilisation Java\ngreetAfterTimeoutMillis(2000);\n<\/pre>\n<p>Comme toujours avec une fonction annot\u00e9e avec <code>@JvmName<\/code>, depuis Kotlin vous l\u2019appelez par son nom Kotlin. Kotlin offre un typage s\u00fbr car vous pouvez seulement envoyer une valeur de type <code>Timeout<\/code> en tant qu&#8217;argument et les unit\u00e9s sont \u00e9videntes dans ce contexte.<\/p>\n<p>\u00c0 partir de Java, vous pouvez envoyer directement une valeur <code>long<\/code>. Cela n&#8217;emp\u00eache plus les erreurs de types et c\u2019est pourquoi cela ne fonctionne pas par d\u00e9faut. Si vous voyez <code>greetAfterTimeout(2)<\/code> dans le code, il n\u2019est pas imm\u00e9diatement \u00e9vident de savoir s\u2019il s\u2019agit de 2 secondes, 2 millisecondes ou 2 ans.<\/p>\n<p>En fournissant l\u2019annotation, vous <em>soulignez<\/em> explicitement votre intention d\u2019appeler cette fonction depuis Java. Un nom descriptif permet d\u2019\u00e9viter toute confusion : l\u2019ajout du suffixe \u00ab\u00a0Millis\u00a0\u00bb au nom de la JVM rend les unit\u00e9s claires pour les utilisateurs de Java.<\/p>\n<h3>Blocs init<\/h3>\n<p><a name = \"init-blocks\"><\/a><\/p>\n<p>Autre am\u00e9lioration pour les classes inline dans la version 1.4.30\u00a0: vous pouvez maintenant d\u00e9finir la logique d\u2019initialisation dans le bloc <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>C&#8217;\u00e9tait interdit auparavant.<\/p>\n<p>Vous pouvez en savoir plus sur les classes inline dans le <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/inline-classes.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a> correspondant, dans la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#improved-inline-classes\" target=\"_blank\" rel=\"noopener\">documentation<\/a> et dans la discussion de <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42434\" target=\"_blank\" rel=\"noopener\">ce ticket<\/a>.<\/p>\n<h3>Classes de valeurs inline<\/h3>\n<p><a name = \"inline-value-classes\"><\/a><\/p>\n<p>Kotlin 1.5 stabilise le concept de classes inline et l\u2019int\u00e8gre \u00e0 une fonctionnalit\u00e9 plus g\u00e9n\u00e9rale : les classes de valeurs.<\/p>\n<p>Jusqu\u2019\u00e0 pr\u00e9sent, les classes \u00ab\u00a0inline\u00a0\u00bb constituaient une fonctionnalit\u00e9 de langage distincte. Elles constituent maintenant une optimisation sp\u00e9cifique de la JVM pour une classe de valeur avec un seul param\u00e8tre. Les classes de valeurs repr\u00e9sentent un concept plus g\u00e9n\u00e9ral et prendront en charge plusieurs optimisations : les classes inline aujourd&#8217;hui et plus tard les classes primitives Valhalla lorsque le projet Valhalla sera disponible (voir <a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2021\/02\/new-language-features-preview-in-kotlin-1-4-30\/#valhalla\">ci-dessous<\/a> pour en savoir plus).<\/p>\n<p>La seule chose qui change pour vous pour le moment est la syntaxe. \u00c9tant donn\u00e9 qu\u2019une classe inline est une classe de valeur optimis\u00e9e, vous devez la d\u00e9clarer diff\u00e9remment :<\/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>Vous d\u00e9finissez une classe de valeurs avec un param\u00e8tre de constructeur et l\u2019annotez avec <code>@JvmInline<\/code>. Nous vous invitons tous \u00e0 utiliser cette nouvelle syntaxe \u00e0 partir de Kotlin 1.5. L\u2019ancienne syntaxe <code>inline class<\/code> continuera \u00e0 fonctionner pendant un certain temps. Un avertissement dans la 1.5 vous informera de son abandon et comprendra une option de migration automatique de toutes vos d\u00e9clarations. Par la suite, elle sera obsol\u00e8te et renverra une erreur.<\/p>\n<h2>Classes de valeurs<\/h2>\n<p><a name = \"value-classes\"><\/a><\/p>\n<p>Une classe <code>value<\/code> repr\u00e9sente une entit\u00e9 immuable avec des donn\u00e9es. Actuellement, une classe <code>value<\/code> ne peut contenir <em>qu&#8217;une seule<\/em> propri\u00e9t\u00e9 pour prendre en charge le cas d\u2019utilisation des \u00ab\u00a0anciennes\u00a0\u00bb classes inline.<\/p>\n<p>Dans les futures versions de Kotlin qui prendront en charge cette fonctionnalit\u00e9, il sera possible de d\u00e9finir des classes de valeurs avec plusieurs propri\u00e9t\u00e9s. Toutes les valeurs doivent \u00eatre des <code>val<\/code> en lecture seule :<\/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>Les classes de valeurs n\u2019ont pas d\u2019identit\u00e9 : elles sont enti\u00e8rement d\u00e9finies par les donn\u00e9es stock\u00e9es et les contr\u00f4les d\u2019identit\u00e9 === ne sont pas autoris\u00e9s pour elles. Le contr\u00f4le d\u2019\u00e9galit\u00e9 == compare automatiquement les donn\u00e9es sous-jacentes.<\/p>\n<p>Cette qualit\u00e9 \u00ab\u00a0sans identit\u00e9\u00a0\u00bb des classes de valeur permettra d\u2019importantes optimisations par la suite : l\u2019arriv\u00e9e du projet Valhalla dans la JVM permettra d\u2019impl\u00e9menter des classes de valeur en tant que classes primitives de la JVM en coulisse.<\/p>\n<p>La contrainte d\u2019immuabilit\u00e9, et donc la possibilit\u00e9 d\u2019optimisations Valhalla, diff\u00e9rencie les classes <code>value<\/code> des classes <code>data<\/code>.<\/p>\n<h3>Futures optimisations avec Valhalla<\/h3>\n<p><a name = \"valhalla\"><\/a><\/p>\n<p>Le <a href=\"https:\/\/openjdk.java.net\/jeps\/8251554\" target=\"_blank\" rel=\"noopener\">project Valhalla<\/a> introduit un nouveau concept dans Java et dans la JVM : les classes primitives.<\/p>\n<p>L\u2019objectif principal des classes primitives est de combiner des primitives performantes avec les avantages orient\u00e9s objet des classes JVM ordinaires. Les classes primitives sont des conteneurs de donn\u00e9es dont les instances peuvent \u00eatre stock\u00e9es dans des variables, sur la pile de calcul, et exploit\u00e9es directement, sans en-t\u00eates ni pointeurs. \u00c0 cet \u00e9gard, elles sont similaires aux valeurs primitives comme <code>int<\/code>, <code>long<\/code>, etc. (en Kotlin, on ne travaille pas directement avec les types primitifs mais le compilateur les g\u00e9n\u00e8re en coulisse).<\/p>\n<p>Les classes primitives pr\u00e9sentent l&#8217;avantage notable de permettre la disposition plane et dense des objets en m\u00e9moire. Actuellement, <code>Array&lt;Point&gt;<\/code> est un tableau de r\u00e9f\u00e9rences. Avec la prise en charge de Valhalla, lorsque l\u2019on d\u00e9finit <code>Point<\/code> comme une classe primitive (dans la terminologie Java) ou comme une classe de valeur avec l\u2019optimisation sous-jacente (dans la terminologie Kotlin), la JVM peut l\u2019optimiser et stocker un tableau de <code>Point<\/code>s dans une disposition \u00ab\u00a0plane\u00a0\u00bb, directement sous la forme d&#8217;un tableau de plusieurs <code>x<\/code> et <code>y<\/code> plut\u00f4t qu&#8217;un tableau de r\u00e9f\u00e9rences.<\/p>\n<p>Nous attendons avec impatience les changements \u00e0 venir dans la JVM et nous voulons que Kotlin en b\u00e9n\u00e9ficie. Pour autant, nous ne voulons pas forcer notre communaut\u00e9 \u00e0 d\u00e9pendre des nouvelles versions de la JVM pour utiliser <code>les classes de valeurs<\/code>, nous allons donc les prendre en charge \u00e9galement pour les versions ant\u00e9rieures de la JVM. Lors de la compilation du code de la JVM avec le prise en charge de Valhalla, les derni\u00e8res optimisations de la JVM fonctionneront pour les classes de valeurs.<\/p>\n<h3>M\u00e9thodes de mutation<\/h3>\n<p><a name = \"mutating-methods\"><\/a><\/p>\n<p>Il y a encore beaucoup \u00e0 dire sur la fonctionnalit\u00e9 de classes de valeurs. Comme les classes de valeurs repr\u00e9sentent des donn\u00e9es \u00ab\u00a0immuables\u00a0\u00bb, des m\u00e9thodes de mutation, comme celles de <a href=\"https:\/\/docs.swift.org\/swift-book\/LanguageGuide\/Methods.html\" target=\"_blank\" rel=\"noopener\">Swift<\/a>, sont possibles pour elles. Une m\u00e9thode de mutation est utilis\u00e9e lorsqu\u2019une fonction membre ou un setter de propri\u00e9t\u00e9 renvoie une nouvelle instance plut\u00f4t que de mettre \u00e0 jour une instance existante. Leur principal avantage est que vous les utilisez avec une syntaxe famili\u00e8re. Ce point doit encore \u00eatre prototyp\u00e9 dans le langage.<\/p>\n<h3>Plus d&#8217;informations<\/h3>\n<p><a name = \"read-more-value-classes\"><\/a><\/p>\n<p>L&#8217;annotation <code>@JvmInline<\/code> est sp\u00e9cifique \u00e0 la JVM. Les classes de valeurs peuvent \u00eatre impl\u00e9ment\u00e9es diff\u00e9remment sur d&#8217;autres backends. Par exemple, sous forme de structs Swift dans Kotlin\/Native.<\/p>\n<p>Vous pouvez en lire plus sur les classes de valeurs dans la <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/notes\/value-classes.md\" target=\"_blank\" rel=\"noopener\">Note de conception pour les classes Kotlin<\/a> ou regarder un extrait de l&#8217;intervention de Roman Elizarov <a href=\"https:\/\/www.youtube.com\/watch?v=0FF19HJDqMo&amp;t=26m32s\" target=\"_blank\" rel=\"noopener\">\u00ab\u00a0A look into the future\u00a0\u00bb<\/a>.<\/p>\n<h2>Prise en charge pour les enregistrements de la JVM<\/h2>\n<p><a name = \"jvm-records\"><\/a><\/p>\n<p>Autre am\u00e9lioration \u00e0 venir dans l\u2019\u00e9cosyst\u00e8me de la JVM\u00a0: <a href=\"https:\/\/openjdk.java.net\/jeps\/395\" target=\"_blank\" rel=\"noopener\">les enregistrements Java<\/a>. Ils sont analogues aux classes <code>data<\/code> de Kotlin et sont principalement de simples conteneurs de donn\u00e9es.<\/p>\n<p>Les enregistrements Java ne suivent pas la convention JavaBeans et ont des m\u00e9thodes \u00ab\u00a0x()\u00a0\u00bb et \u00ab\u00a0y()\u00a0\u00bb au lieu des m\u00e9thodes famili\u00e8res \u00ab\u00a0getX()\u00a0\u00bb et \u00ab\u00a0getY()\u00a0\u00bb.<\/p>\n<p>L\u2019interop\u00e9rabilit\u00e9 avec Java a toujours \u00e9t\u00e9 et reste une priorit\u00e9 pour Kotlin. Ainsi, le code Kotlin \u00ab\u00a0comprend\u00a0\u00bb les nouveaux enregistrements Java et les consid\u00e8re comme des classes ayant des propri\u00e9t\u00e9s Kotlin. Cela fonctionne comme pour les classes Java normales suivant la convention 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>Principalement pour des raisons d\u2019interop\u00e9rabilit\u00e9, vous pouvez annoter votre classe <code>data<\/code> avec <code>@JvmRecord<\/code> pour que de nouvelles m\u00e9thodes d\u2019enregistrement JVM soient g\u00e9n\u00e9r\u00e9es :<\/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>L\u2019annotation <code>@JvmRecord<\/code> permet au compilateur de g\u00e9n\u00e9rer les m\u00e9thodes <code>x()<\/code> et <code>y()<\/code> au lieu des m\u00e9thodes standard <code>getX()<\/code> et <code>getY()<\/code>. Nous supposons qu\u2019il vous suffit d\u2019utiliser cette annotation pour pr\u00e9server l\u2019API de la classe lors de la conversion de Java en Kotlin. Dans tous les autres cas d\u2019utilisation, les classes <code>data<\/code> famili\u00e8res de Kotlin peuvent s&#8217;utiliser \u00e0 la place sans probl\u00e8me.<\/p>\n<p>Cette annotation n\u2019est disponible que si vous compilez le code Kotlin vers une version 15+ de la JVM. Vous pouvez en savoir plus sur cette fonctionnalit\u00e9 dans le <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/jvm-records.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a> correspondant, dans la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#jvm-records-support\" target=\"_blank\" rel=\"noopener\">documentation<\/a> et dans la discussion de <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42430\" target=\"_blank\" rel=\"noopener\">ce ticket<\/a>.<\/p>\n<h2>Am\u00e9liorations des interfaces et des classes scell\u00e9es<\/h2>\n<p><a name = \"sealed-interfaces\"><\/a><\/p>\n<p>Lorsque vous d\u00e9clarez une classe sealed, cela restreint la hi\u00e9rarchie \u00e0 des sous-classes d\u00e9finies, ce qui permet des v\u00e9rifications exhaustives dans les branches <code>when<\/code>. Dans Kotlin 1.4, la hi\u00e9rarchie des classes scell\u00e9es comporte deux contraintes. Premi\u00e8rement, la classe sup\u00e9rieure ne peut pas \u00eatre une interface scell\u00e9e, ce doit \u00eatre une classe. Deuxi\u00e8mement, toutes les sous-classes doivent se trouver dans le m\u00eame fichier.<\/p>\n<p>Kotlin 1.5 supprime ces deux contraintes : vous pouvez d\u00e9sormais cr\u00e9er une <em>interface<\/em> scell\u00e9e. Les sous-classes (tant pour les classes scell\u00e9es que pour les interfaces scell\u00e9es) doivent se trouver dans la m\u00eame unit\u00e9 de compilation et dans le m\u00eame paquet que la super classe, mais elles peuvent maintenant se trouver dans des fichiers <em>diff\u00e9rents<\/em>.<\/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>Les classes scell\u00e9es, et maintenant les interfaces scell\u00e9es, sont utiles pour d\u00e9finir des hi\u00e9rarchies de types de donn\u00e9es abstraites (ADT).<\/p>\n<p>Another important use case that can now be nicely addressed with sealed interfaces is closing an interface for inheritance and implementation outside the library. D\u00e9finir une interface comme sealed restreint son impl\u00e9mentation \u00e0 la m\u00eame unit\u00e9 de compilation et au m\u00eame paquet, ce qui, dans le cas d\u2019une biblioth\u00e8que, rend impossible son impl\u00e9mentation en dehors de la biblioth\u00e8que.<\/p>\n<p>Par exemple, l\u2019interface <code>Job<\/code> du paquet <code>kotlinx.coroutines<\/code> est uniquement destin\u00e9e \u00e0 \u00eatre impl\u00e9ment\u00e9e \u00e0 l\u2019int\u00e9rieur de la biblioth\u00e8que <code>kotlinx.coroutines<\/code>. Le fait de la rendre <code>sealed<\/code> rend cette intention explicite :<\/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>En tant qu\u2019utilisateur de la biblioth\u00e8que, vous n\u2019\u00eates plus autoris\u00e9 \u00e0 d\u00e9finir votre propre sous-classe de <code>Job<\/code>. Cela a toujours \u00e9t\u00e9 \u00ab\u00a0implicite\u00a0\u00bb, mais avec les interfaces scell\u00e9es, le compilateur peut formellement l\u2019interdire.<\/p>\n<h3>Utiliser la prise en charge de la JVM \u00e0 l\u2019avenir<\/h3>\n<p><a name = \"new-sealed-jvm-support\"><\/a><\/p>\n<p>La prise en charge de l\u2019aper\u00e7u des classes scell\u00e9es a \u00e9t\u00e9 inaugur\u00e9e dans la version Java 15 et sur la JVM. \u00c0 l\u2019avenir, nous allons utiliser la prise en charge naturelle de la JVM pour les classes scell\u00e9es si vous compilez le code Kotlin avec la derni\u00e8re JVM (tr\u00e8s probablement la JVM 17 ou une version ult\u00e9rieure lorsque cette fonctionnalit\u00e9 sera stable).<\/p>\n<p>En Java, vous listez explicitement toutes les sous-classes de la classe ou de l\u2019interface scell\u00e9e en question\u00a0:<\/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>Ces informations sont stock\u00e9es dans le fichier de la classe \u00e0 l\u2019aide du nouvel attribut <code>PermittedSubclasses<\/code>. La JVM reconna\u00eet les classes scell\u00e9es au moment de l\u2019ex\u00e9cution et emp\u00eache leur extension par sous-classes non autoris\u00e9es.<\/p>\n<p>\u00c0 l\u2019avenir, lorsque vous compilerez Kotlin sur la derni\u00e8re JVM, cette nouvelle prise en charge de JVM pour les classes scell\u00e9es sera utilis\u00e9e. En coulisse, le compilateur va g\u00e9n\u00e9rer une liste de sous-classes autoris\u00e9es dans le bytecode pour s\u2019assurer que la JVM est prise en charge et proc\u00e9der \u00e0 des v\u00e9rifications suppl\u00e9mentaires lors de l\u2019ex\u00e9cution.<\/p>\n<pre class=\"kotlin-code\" data-highlight-only=\"true\" theme=\"idea\" indent=\"4\" style=\"visibility: hidden; padding: 36px 0;\">\n\/\/ pour la JVM 17 or later\nExpr::class.java.permittedSubclasses \/\/ [Const, Sum, NotANumber]\n<\/pre>\n<p>En Kotlin, vous n\u2019avez pas besoin de sp\u00e9cifier la liste de sous-classes ! Le compilateur g\u00e9n\u00e9rera la liste en fonction des sous-classes d\u00e9clar\u00e9es dans le m\u00eame paquet.<\/p>\n<p>La possibilit\u00e9 de sp\u00e9cifier explicitement les sous-classes pour une super classe ou une interface pourrait \u00eatre ajout\u00e9e ult\u00e9rieurement comme sp\u00e9cification optionnelle. Pour le moment, nous pensons que cela ne sera pas n\u00e9cessaire, mais nous attendons de conna\u00eetre vos cas d\u2019utilisation pour savoir si vous avez besoin de cette fonctionnalit\u00e9 !<\/p>\n<p>Veuillez noter que pour les anciennes versions de la JVM, il est th\u00e9oriquement possible de d\u00e9finir une sous-classe Java pour l\u2019interface scell\u00e9e de Kotlin, mais ne le faites pas ! \u00c9tant donn\u00e9 que la prise en charge de la JVM pour les sous-classes autoris\u00e9es n\u2019est pas encore disponible, cette contrainte n\u2019est appliqu\u00e9e que par le compilateur Kotlin. Nous ajouterons des avertissements dans l&#8217;IDE pour \u00e9viter que cela ne se produise accidentellement. Par la suite, le nouveau m\u00e9canisme sera utilis\u00e9 pour les derni\u00e8res versions de la JVM afin de v\u00e9rifier l&#8217;absence de sous-classes \u00ab\u00a0non autoris\u00e9es\u00a0\u00bb de Java.<\/p>\n<p>Vous pouvez en savoir plus sur les interfaces scell\u00e9es et les restrictions rel\u00e2ch\u00e9es des classes scell\u00e9es dans le <a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/sealed-interface-freedom.md\" target=\"_blank\" rel=\"noopener\">KEEP<\/a> correspondant ou dans la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html#sealed-interfaces\" target=\"_blank\" rel=\"noopener\">documentation<\/a> et consulter la discussion dans <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42433\" target=\"_blank\" rel=\"noopener\">ce ticket<\/a>.<\/p>\n<h2>Comment essayer les nouvelles fonctionnalit\u00e9s<\/h2>\n<p><a name = \"how-to-try\"><\/a><\/p>\n<p>Vous devez utiliser Kotlin 1.4.30. Sp\u00e9cifiez la <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/compiler-reference.html#-language-version-version\" target=\"_blank\" rel=\"noopener\">version<\/a> 1.5 du langage pour activer les nouvelles fonctionnalit\u00e9s :<\/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>Pour essayer les enregistrements JVM, vous devez en outre utiliser jvmTarget 15 et activer les fonctions d&#8217;aper\u00e7u de la JVM : ajoutez les options de compilation <code>-language-version 1.5<\/code> et <code>-Xjvm-enable-preview<\/code>.<\/p>\n<h3>Notes de pr\u00e9-version<\/h3>\n<p>Notez que la prise en charge des nouvelles fonctionnalit\u00e9s est exp\u00e9rimentale et que la prise en charge de la version 1.5 du langage est en phase de pr\u00e9-publication. Param\u00e9trer la version du langage en 1.5 dans le compilateur Kotlin 1.4.30 \u00e9quivaut \u00e0 essayer la preview 1.5-M0. Les garanties de r\u00e9trocompatibilit\u00e9 ne couvrent pas les versions en pr\u00e9-publication. Les fonctionnalit\u00e9s et l\u2019API peuvent changer dans les versions ult\u00e9rieures. Lorsque nous arriverons \u00e0 la version finale Kotlin 1.5-RC, tous les binaires produits par les versions de pr\u00e9-publication seront interdits par le compilateur et vous devrez recompiler tout le code compil\u00e9 par 1.5-Mx.<\/p>\n<h3>Faites-nous part de vos commentaires<\/h3>\n<p>Essayez les nouvelles fonctionnalit\u00e9s d\u00e9crites dans ce post et partagez vos retours avec nous ! Vous pouvez trouver plus de d\u00e9tails dans les KEEP, participer aux discussions dans YouTrack et nous signaler d&#8217;\u00e9ventuels incidents. Faites-nous part de vos observations sur l&#8217;efficacit\u00e9 des nouvelles fonctionnalit\u00e9s pour les cas d\u2019utilisation de vos projets !<\/p>\n<p>Lectures et discussions compl\u00e9mentaires :<\/p>\n<ul>\n<li><a href=\"https:\/\/kotlinlang.org\/docs\/reference\/whatsnew1430.html\" target=\"_blank\" rel=\"noopener\">Page de documentation \u00ab\u00a0Nouveaut\u00e9s\u00a0\u00bb<\/a>.<\/li>\n<li><a href=\"https:\/\/github.com\/Kotlin\/KEEP\/blob\/master\/proposals\/inline-classes.md\" target=\"_blank\" rel=\"noopener\">KEEP Classes inline<\/a> ; discussion : <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\">Document de conception des classes de valeur<\/a> ; discussion dans <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\">Enregistrements JVM KEEP<\/a> ; discussion : <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 scell\u00e9es et classes scell\u00e9es KEEP<\/a> ; discussion : <a href=\"https:\/\/youtrack.jetbrains.com\/issue\/KT-42433\" target=\"_blank\" rel=\"noopener\">KT-42433<\/a>.<\/li>\n<p>Auteur de l&#8217;article original en anglais : <a href=\"https:\/\/blog.jetbrains.com\/author\/svetlana-isakova\/\" target=\"_blank\" rel=\"noopener noreferrer\">Svetlana Isakova<\/a><\/p>\n","protected":false},"author":813,"featured_media":113696,"comment_status":"closed","ping_status":"closed","template":"","categories":[],"tags":[],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/kotlin\/127158"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/kotlin"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/kotlin"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=127158"}],"version-history":[{"count":1,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/kotlin\/127158\/revisions"}],"predecessor-version":[{"id":127160,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/kotlin\/127158\/revisions\/127160"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/113696"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=127158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=127158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=127158"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=127158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}