IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Kotlin 1.6.0 est disponible et introduit de nouvelles fonctionnalités de langage
Des optimisations et des améliorations des fonctionnalités existantes

Le , par Stéphane le calme

91PARTAGES

9  0 
Kotlin 1.6.0 est disponible et introduit de nouvelles fonctionnalités de langage, des optimisations et des améliorations des fonctionnalités existantes, ainsi que de nombreuses améliorations de la bibliothèque standard Kotlin. Certaines fonctionnalités deviennent stables dans cette version. Kotlin 1.6.0 s'accompagne de Kover, un plugin Gradle pour les agents de couverture de code IntelliJ et JaCoCo Kotlin, et d'un nouveau gestionnaire de mémoire pour Kotlin/Native.

Language

Kotlin 1.6.0 apporte une stabilisation à plusieurs fonctionnalités du langage introduites pour la prévisualisation dans la version 1.5.30 précédente.

Les instructions exhaustives when pour les déclarations avec une énumération, des classes scellées ou des booléens

Commençons par ce rappel :
  • une classe scellée est une classe qui retreint la hiérarchie de ses classes. Elle est donc utilisée pour représenter une hiérarchie de classe restreinte où une valeur ou un objet peut avoir l'un des types d'un ensemble de types ;
  • une énumération est un type de données utilisé pour définir un ensemble de constantes. Dans Kotlin, chaque constante de l'énumération est un objet . Ces constantes sont séparées par des virgules ;
  • un booléen représente une valeur qui peut être soit vraie, soit fausse.

Une instruction when exhaustive contient des branches pour tous les types ou valeurs possibles de son sujet, ou pour certains types plus une branche else. Il couvre tous les cas possibles, rendant votre code plus sûr.

JetBrains va bientôt interdire les instructions when non exhaustives pour rendre le comportement cohérent avec les expressions when. Pour assurer une migration en douceur, Kotlin 1.6.0 signale des avertissements non exhaustifs when avec des déclarations comportant des énumérations, des classes scellées ou des booléens. Ces avertissements deviendront des erreurs dans les versions futures.

Code Kotlin : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sealed class Contact {
    data class PhoneCall(val number: String) : Contact()
    data class TextMessage(val number: String) : Contact()
}
 
fun Contact.messageCost(): Int =
    when(this) { // Error: 'when' expression must be exhaustive
        is Contact.PhoneCall -> 42
    }
 
fun sendMessage(contact: Contact, message: String) {
    // Starting with 1.6.0
 
    // Warning: Non exhaustive 'when' statements on Boolean will be
    // prohibited in 1.7, add 'false' branch or 'else' branch instead
    when(message.isEmpty()) {
        true -> return
    }
    // Warning: Non exhaustive 'when' statements on sealed class/interface will be
    // prohibited in 1.7, add 'is TextMessage' branch or 'else' branch instead
    when(contact) {
        is Contact.PhoneCall -> TODO()
    }
}

Fonctions de suspension stables en tant que supertypes

Kotlin 1.6.0 rend la mise en œuvre de la suspension des types fonctionnels stable. Un aperçu était disponible dans Kotlin 1.5.30.

La fonctionnalité peut être utile lors de la conception d'API qui utilisent les coroutines Kotlin et acceptent la suspension des types fonctionnels. Vous pouvez maintenant rationaliser votre code en enfermant le comportement souhaité dans une classe distincte qui implémente un type fonctionnel de suspension.

Code Kotlin : Sélectionner tout
1
2
3
4
5
class MyClickAction : suspend () -> Unit {
    override suspend fun invoke() { TODO() }
}
 
fun launchOnClick(action: suspend () -> Unit) {}

Vous pouvez utiliser une instance de cette classe où seules les références lambda et les fonctions de suspension étaient autorisées auparavant : launchOnClick(MyClickAction()).

Il existe actuellement deux limitations provenant des détails de mise en œuvre :
  • vous ne pouvez pas mélanger des types fonctionnels ordinaires et des types suspendus dans la liste des supertypes ;
  • vous ne pouvez pas utiliser plusieurs supertypes fonctionnels suspendus.

Conversions suspendues stables

Kotlin 1.6.0 introduit les conversions stables des types fonctionnels normaux aux types fonctionnels suspendus. À partir de la version 1.4.0, la fonctionnalité prenait en charge les littéraux fonctionnels et les références appelables. Avec la 1.6.0, il fonctionne avec n'importe quelle forme d'expression. En tant qu'argument d'appel, vous pouvez désormais transmettre n'importe quelle expression d'un type fonctionnel régulier approprié où une suspension est attendue. Le compilateur effectuera automatiquement une conversion implicite.

Code Kotlin : Sélectionner tout
1
2
3
4
5
6
7
8
9
fun getSuspending(suspending: suspend () -> Unit) {}
 
fun suspending() {}
 
fun test(regular: () -> Unit) {
    getSuspending { }           // OK
    getSuspending(::suspending) // OK
    getSuspending(regular)      // OK
}

Instanciation stable des classes d'annotation

Kotlin 1.5.30 a introduit la prise en charge expérimentale de l'instanciation des classes d'annotation sur la plate-forme JVM. Avec la 1.6.0, la fonctionnalité est disponible par défaut à la fois pour Kotlin/JVM et Kotlin/JS.

Inférence de type améliorée pour les types génériques récursifs

Kotlin 1.5.30 a introduit une amélioration de l'inférence de type pour les types génériques récursifs, ce qui a permis d'inférer leurs arguments de type en se basant uniquement sur les limites supérieures des paramètres de type correspondants. L'amélioration était disponible avec l'option du compilateur. Dans les versions 1.6.0 et supérieures, elle est activée par défaut.

Code Kotlin : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Before 1.5.30
val containerA = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:13-alpine")).apply {
  withDatabaseName("db")
  withUsername("user")
  withPassword("password")
  withInitScript("sql/schema.sql")
}
 
// With compiler option in 1.5.30 or by default starting with 1.6.0
val containerB = PostgreSQLContainer(DockerImageName.parse("postgres:13-alpine"))
  .withDatabaseName("db")
  .withUsername("user")
  .withPassword("password")
  .withInitScript("sql/schema.sql")

Modifications apportées à l'inférence du générateur (builder)

L'inférence de générateur est une variante d'inférence de type qui est utile lors de l'appel de fonctions de générateur génériques. Il peut déduire les arguments de type d'un appel à l'aide des informations de type des appels à l'intérieur de son argument lambda.

JetBrains apporte de nombreux changements qui se rapprochent d'une inférence de générateur entièrement stable. À partir de Kotlin 1.6.0 :
  • vous pouvez effectuer des appels renvoyant une instance d'un type pas encore déduit dans un lambda de générateur sans spécifier l'option de compilateur -Xunrestricted-builder-inference introduite dans Kotlin 1.5.30 ;
  • avec -Xenable-builder-inference, vous pouvez écrire vos propres générateurs sans appliquer l'annotation @BuilderInference ;
  • avec -Xenable-builder-inference, l'inférence de générateur s'active automatiquement si une inférence de type normale ne peut pas obtenir suffisamment d'informations sur un type.

Prise en charge des annotations sur les paramètres de type de classe

La prise en charge des annotations sur les paramètres de type de classe ressemble à ceci :

Code Kotlin : Sélectionner tout
1
2
3
4
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class BoxContent
 
class Box<@BoxContent T> {}

Les annotations sur tous les paramètres de type sont émises dans le bytecode JVM afin que les processeurs d'annotations puissent les utiliser.

Prise en charge des versions précédentes de l'API pendant une période plus longue

À partir de Kotlin 1.6.0, JetBrains prendra en charge le développement de trois versions précédentes de l'API au lieu de deux, ainsi que la version stable actuelle. Actuellement, sont prises en charge les versions 1.3, 1.4, 1.5 et 1.6.

Kotlin/JVM

Pour Kotlin/JVM, à partir de la version 1.6.0, le compilateur peut générer des classes avec une version de bytecode correspondant à JVM 17. La nouvelle version du langage inclut également des propriétés déléguées optimisées et des annotations reproductibles.

Annotations répétables avec rétention d'exécution pour la cible JVM 1.8

Java 8 a introduit des annotations reproductibles, qui peuvent être appliquées plusieurs fois à un seul élément de code. La fonctionnalité nécessite la présence de deux déclarations dans le code Java : l'annotation répétable elle-même marquée par @java.lang.annotation.Repeatable et l'annotation contenante pour conserver ses valeurs.

Kotlin a également des annotations répétables, mais ne nécessite que @kotlin.annotation.Repeatable pour être présent sur une déclaration d'annotation pour la rendre répétable. Avant la version 1.6.0, la fonctionnalité ne prenait en charge que la rétention SOURCE et était incompatible avec les annotations répétables de Java. Kotlin 1.6.0 supprime ces limitations. @kotlin.annotation.Repeatable accepte désormais toute rétention et rend l'annotation répétable à la fois dans Kotlin et Java. Les annotations répétables de Java sont désormais également prises en charge du côté Kotlin.

Bien que vous puissiez déclarer une annotation contenante, ce n'est pas nécessaire. Par exemple :

  • si une annotation @Tag est marquée avec @kotlin.annotation.Repeatable, le compilateur Kotlin génère automatiquement une classe d'annotation conteneur sous le nom de @Tag.Container :

    Code Kotlin : Sélectionner tout
    1
    2
    3
    4
    @Repeatable
    annotation class Tag(val name: String)
     
    // The compiler generates @Tag.Container containing annotation
  • pour définir un nom personnalisé pour une annotation conteneur, appliquez la méta-annotation @kotlin.jvm.JvmRepeatable et transmettez la classe d'annotation conteneur explicitement déclarée en tant qu'argument :

    Code Kotlin : Sélectionner tout
    1
    2
    3
    4
    @JvmRepeatable(Tags::class)
    annotation class Tag(val name: String)
     
    annotation class Tags(val value: Array<Tag>)


La réflexion Kotlin prend désormais en charge les annotations répétables de Kotlin et de Java via une nouvelle fonction, KAnnotatedElement.findAnnotations().

Optimiser les propriétés déléguées qui appellent get/set sur l'instance KProperty donnée

JetBrains a optimisé le bytecode JVM généré en omettant le champ [C]$delegate[/] et en générant un accès immédiat à la propriété référencée.

Par exemple, dans le code suivant :

Code Kotlin : Sélectionner tout
1
2
3
4
5
class Box<T> {
    private var impl: T = ...
 
    var content: T by ::impl
}

Kotlin ne génère plus le champ content$delegate. Les accesseurs de propriété de la variable de contenu invoquent directement la variable impl, en sautant les opérateurs getValue/setValue de la propriété déléguée et en évitant ainsi le besoin de l'objet de référence de propriété du type KProperty.

Kotlin/Native

Kotlin/Native reçoit de nombreuses améliorations et mises à jour de composants, dont certaines à l'état d'aperçu :
  • aperçu du nouveau gestionnaire de mémoire ;
  • prise en charge de Xcode 13 ;
  • compilation de cibles Windows sur n'importe quel hôte ;
  • mises à jour de LLVM et de l'éditeur de liens ;
  • amélioration des performances ;
  • plugin de compilateur unifié ABI avec backends JVM et JS IR ;
  • messages d'erreur détaillés pour les échecs de liaison klib ;
  • API de gestion des exceptions non gérée retravaillée.

Aperçu du nouveau gestionnaire de mémoire

Avec Kotlin 1.6.0, vous pouvez essayer l'aperçu de développement du nouveau gestionnaire de mémoire Kotlin/Native. Avec cette fonctionnalité, JetBrains se rapproche de la fourniture d'une expérience de développeur cohérente dans les projets multiplateformes. Cela signifie que le nouveau gestionnaire de mémoire lève les restrictions existantes sur le partage d'objets entre les threads et fournit des primitives de programmation simultanée entièrement sans fuite et ne nécessite aucune gestion ou annotation spéciale de la part des développeurs.

L'un des changements notables est l'initialisation paresseuse des propriétés de niveau supérieur, comme dans Kotlin/JVM. Une propriété de niveau supérieur est initialisée lorsqu'une propriété ou une fonction de niveau supérieur du même fichier est accédée pour la première fois. Ce mode inclut également l'optimisation interprocédurale globale (activée uniquement pour les versions binaires), qui supprime les contrôles d'initialisation redondants.

Prise en charge de Xcode 13

Kotlin/Native 1.6.0 prend en charge Xcode 13 – la dernière version de Xcode. N'hésitez pas à mettre à jour votre Xcode et à continuer à travailler sur vos projets Kotlin pour les systèmes d'exploitation Apple.

Compilation de cibles Windows sur n'importe quel hôte

À partir de la version 1.6.0, vous n'avez pas besoin d'un hôte Windows pour compiler les cibles Windows mingwX64 et mingwX86. Ils peuvent être compilés sur n'importe quel hôte prenant en charge Kotlin/Native.

Mises à jour de LLVM et de l'éditeur de liens

JetBrains a retravaillé la dépendance LLVM que Kotlin/Native utilise sous le capot. Cela apporte divers avantages, notamment :
  • mise à jour de la version LLVM vers 11.1.0 ;
  • taille de dépendance réduite. Par exemple, sur macOS, il est désormais d'environ 300 Mo au lieu de 1200 Mo dans la version précédente ;
  • dépendance exclue sur la bibliothèque ncurses5 qui n'est pas disponible dans les distributions Linux modernes.

En plus de la mise à jour LLVM, Kotlin/Native utilise désormais l'éditeur de liens LLD (un éditeur de liens du projet LLVM) pour les cibles MingGW. Il offre divers avantages par rapport à l'éditeur de liens ld.bfd précédemment utilisé et nous permettra d'améliorer les performances d'exécution des binaires produits et de prendre en charge les caches du compilateur pour les cibles MinGW. Notez que LLD nécessite des bibliothèques d'importation pour la liaison DLL.

Améliorations des performances

Kotlin/Native 1.6.0 offre les améliorations de performances suivantes :
  • temps de compilation : les caches du compilateur sont activés par défaut pour les cibles linuxX64 et iosArm64. Cela accélère la plupart des compilations en mode débogage (sauf la première). Les mesures ont montré une augmentation de la vitesse d'environ 200 % sur nos projets de test. Les caches du compilateur sont disponibles pour ces cibles depuis Kotlin 1.5.0 avec des propriétés Gradle supplémentaires ; vous pouvez les supprimer maintenant ;
  • temps d'exécution : l'itération sur des tableaux avec des boucles for est désormais jusqu'à 12 % plus rapide grâce aux optimisations dans le code LLVM produit.

Plugin de compilateur unifié ABI avec backends JVM et JS IR

Dans les versions précédentes, les auteurs de plugins de compilateur devaient fournir des artefacts séparés pour Kotlin/Native en raison des différences dans l'ABI.

À partir de la version 1.6.0, le plugin Kotlin Multiplatform Gradle est capable d'utiliser le compilateur jar intégrable - celui utilisé pour les backends JVM et JS IR - pour Kotlin/Native. Il s'agit d'une étape vers l'unification de l'expérience de développement de plug-in de compilateur, car vous pouvez désormais utiliser les mêmes artefacts de plug-in de compilateur pour Native et d'autres plates-formes prises en charge.

Il s'agit d'une version préliminaire d'un tel support, et il nécessite un opt-in. Pour commencer à utiliser les artefacts de plug-in de compilateur générique pour Kotlin/Native, ajoutez la ligne suivante à gradle.properties: kotlin.native.useEmbeddableCompilerJar=trueJetBrains prévoit d'utiliser le compilateur jar intégrable pour Kotlin/Native par défaut à l'avenir, il est donc essentiel pour l'éditeur de savoir comment la Preview marche pour les développeurs.

Messages d'erreur détaillés pour les échecs de liaison klib

Le compilateur Kotlin/Native fournit désormais des messages d'erreur détaillés pour les erreurs de liaison klib. Les messages contiennent désormais des descriptions d'erreur claires et incluent également des informations sur les causes possibles et les moyens de les corriger.

Par exemple:
  • 1.5.30:
    Code : Sélectionner tout
    1
    2
    e: java.lang.IllegalStateException: IrTypeAliasSymbol expected: Unbound public symbol for public kotlinx.coroutines/CancellationException|null[0]
    <stack trace>
  • 1.6.0:
    Code : Sélectionner tout
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, kotlinx.coroutines/CancellationException|null[0].
    IrTypeAliasSymbol is expected.
    
    This could happen if there are two libraries, where one library was compiled against the different version of the other library than the one currently used in the project.
    Please check that the project configuration is correct and has consistent versions of dependencies.
    
    The list of libraries that depend on "org.jetbrains.kotlinx:kotlinx-coroutines-core (org.jetbrains.kotlinx:kotlinx-coroutines-core-macosx64)" and may lead to conflicts:
    <list of libraries and potential version mismatches>
    
    Project dependencies:
    <dependencies tree>

API de gestion des exceptions

JetBrains a unifié le traitement des exceptions non gérées dans l'environnement d'exécution Kotlin/Native et exposé le traitement par défaut en tant que fonction processUnhandledException(throwable*: Throwable) pour une utilisation par des environnements d'exécution personnalisés, comme kotlinx.coroutines. Ce traitement est également appliqué aux exceptions qui échappent à l'opération dans Worker.executeAfter(), mais uniquement pour le nouveau gestionnaire de mémoire.

Les améliorations de l'API ont également affecté les crochets qui ont été définis par setUnhandledExceptionHook(). Auparavant, ces hooks étaient réinitialisés après que le runtime Kotlin/Native ait appelé le hook avec une exception non gérée, et le programme se terminait toujours juste après. Maintenant, ces crochets peuvent être utilisés plus d'une fois, et si vous voulez que le programme se termine toujours sur une exception non gérée, ne définissez pas de crochet d'exception non géré (setUnhandledExceptionHook()), ou assurez-vous d'appeler terminateWithUnhandledException() à la fin de votre crochet. Cela vous aidera à envoyer des exceptions à un service de rapport d'incident tiers (comme Firebase Crashlytics), puis à mettre fin au programme. Les exceptions qui échappent à main() et les exceptions qui traversent la limite d'interopérabilité termineront toujours le programme, même si le hook n'a pas appelé terminateWithUnhandledException().

Kotlin/JS

JetBrains continue à travailler sur la stabilisation du backend IR pour le compilateur Kotlin/JS. Kotlin/JS a maintenant une option pour désactiver le téléchargement de Node.js et Yarn.

Source : note de version

Une erreur dans cette actualité ? Signalez-le nous !