Premier aperçu de Kotlin 1.4-M2 : améliorations de la bibliothèque standard

Nous continuons de travailler sur Kotlin 1.1.4 et la prochaine preview 1.4-M2 est pour bientôt. En attendant la preview, nous sommes prêts à vous dévoiler quelques unes de ses principales améliorations.

Dans cet article, nous vous présentons les évolutions de la bibliothèque standard :

Bien que Kotlin 1.4-M2 ne soit pas encore sorti, nous avons déployé sa première version sur Kotlin playground afin que vous puissiez essayer tout ce que vous trouverez dans cet article. Les exemples de code présentés dans cet article fonctionnent également avec la nouvelle version.

Si vous avez hâte d’essayer la version 1.4-M2 à venir, inscrivez-vous à la newsletter du blog Kotlin pour être notifié de sa disponibilité.

 

Extension de la bibliothèque commune

Vous pouvez utiliser la bibliothèque standard dans le code “commun”, c’est-à-dire le code partagé entre différentes plateformes, qu’il s’agisse d’Android et iOS ou de JVM et JS. Nous étendons progressivement la bibliothèque commune et y ajoutons des fonctionnalités.

La précédente implémentation de appendln dans Kotlin/JVM a apporté un séparateur de ligne dépendant du système (\n sur les systèmes UNIX et \r\n sur Windows). Cependant, nous pensons qu’il est important de garantir le même comportement indépendamment du système d’exploitation et de la plateforme sous-jacente si nous parlons de code commun. C’est pourquoi nous avons abandonné la fonction appendln au profit de la nouvelle fonction appendLine, qui termine toujours les lignes avec un caractère unique \n :

Vous pouvez toujours utiliser System.lineSeparator() dans la JVM lorsque vous avez besoin d’un séparateur spécifique à la plateforme.

Les autres fonctions qui peuvent maintenant être utilisées dans le code commun vous permettent d’utiliser la représentation de chaîne de la trace de pile indiquée. L’extension Throwable.stackTraceToString() renvoie la description détaillée de ce throwable avec sa trace de pile, et Throwable.printStackTrace() imprime cette description sur la sortie d’erreur standard.

Dans le code commun, vous pouvez également utiliser la fonction Throwable.addSuppressed(), qui vous permet de spécifier les exceptions qui ont été supprimées afin de délivrer l’exception, et la propriété Throwable.suppressedExceptions, qui renvoie une liste de toutes les exceptions supprimées.

Nouvelles fonctions de tableau

Nous avons ajouté de nouvelles fonctions d’extension pour les tableaux afin de vous proposer une expérience plus harmonieuse lorsque vous travaillez avec différents types de conteneurs  :

  • shuffle() – place les éléments du tableau dans un ordre aléatoire.
  • onEach() – effectue l’action indiquée sur chaque élément du tableau et retourne le tableau lui-même.

Ces fonctions devraient être familières à ceux qui utilisent les listes ; elles fonctionnent de la même manière pour les tableaux.

Nous avons également ajouté de nouvelles fonctions pour le tri des sous-plages de tableaux. Auparavant, la fonction sort() avec les paramètres fromIndex et toIndex, était limitée à la JVM. Cette fonction est désormais commune, et non plus limitée à la JVM, de même que deux nouvelles fonctions connexes, qui sont des versions sous-plages de reverse() et sortDescending(). Chacune d’entre elles prend deux index et réordonne les éléments entre eux (en incluant fromIndex mais en excluant toIndex), de la manière indiquée par leur nom :

  • reverse() pour les sous-plages de tableau inverse l’ordre des éléments dans la sous-plage.
  • sortDescending() pour les sous-plages de tableau trie les éléments de la sous-plage par ordre décroissant.

Nouvelles fonctions de l’API des collections

Dans la version 1.4-M2, nous continuons à développer l’API des collections dans la bibliothèque standard pour couvrir davantage de cas d’utilisation réels :

  • Une nouvelle fonction setOfNotNull() crée un ensemble composé de tous les éléments non null parmi les arguments fournis.
  • shuffled() est maintenant disponible pour les séquences.
  • onEachIndexed() et reduceIndexedOrNull() ont été respectivement ajoutés comme équivalents de onEach() et reduceOrNull(). Comme vous le savez peut-être déjà, Indexed dans le nom d’une fonction de traitement de collection signifie que l’opération appliquée a l’index d’élément comme paramètre.
  • runningFold() et runningReduce() ont été ajoutés comme synonymes de scan() et scanReduce(). Ces noms sont plus cohérents avec les fonctions connexes fold() et reduce(). À l’avenir, scan() sera disponible avec runningFold() car c’est un nom couramment utilisé pour cette opération. Cependant, la fonction expérimentale scanReduce() sera bientôt abandonnée et supprimée.

Amélioration de l’API existante

Kotlin 1.4 étant une version majeure, nous pouvons apporter de nouvelles fonctionnalités au langage et de nouvelles fonctions ou interfaces à la bibliothèque standard. Nous n’ajoutons de nouvelles déclarations expérimentales que dans les versions incrémentielles (comme la version 1.3.70). Si vous écrivez du code avec Kotlin 1.3.70 et que vous n’utilisez pas de déclarations expérimentales, votre code sera très bien compilé pour vos collaborateurs utilisant Kotlin 1.3.40.

Les versions majeures n’ont pas besoin d’obéir aux mêmes règles strictes que les versions mineures, ce qui signifie que si vous utilisez une nouvelle fonctionnalité ou API, le compilateur Kotlin de la version 1.3 ne peut pas compiler le code écrit en Kotlin 1.4. Cela nous permet d’apporter des modifications à l’API afin de l’améliorer. Nous veillons à la rétrocompatibilité afin que le code écrit pour l’ancienne version continue de se compiler et de fonctionner comme auparavant.

Dans Kotlin 1.4, nous avons assoupli plusieurs fonctions pour accepter des valeurs null :

Kotlin 1.3 ne compilera pas ce code car il exige que le récepteur de String.toBoolean() soit non-nullable. Kotlin 1.4 change le recepteur en une chaîne nullable : String?.toBoolean(). Néanmoins, tout le code que vous avez écrit auparavant continue de compiler et de fonctionner avec Kotlin 1.4.

La même logique s’applique au récepteur Array des fonctions contentEquals, contentHashCode et contentToString : il est maintenant nullable. De même, String.format() permet désormais d’utiliser null comme argument locale, auquel cas aucune localisation n’est appliquée.

Les constantes suivantes définies dans Double et Float sont désormais des constantes “réelles” :

Elles sont maintenant définies comme des variables const , vous pouvez donc les utiliser comme arguments d’annotation.

SIZE_BITS et SIZE_BYTES sont de nouvelles constantes dans Double et Float ; elles contiennent le nombre de bits et d’octets utilisés pour représenter une instance du type sous forme binaire.

Notez que nous avons également modifié les valeurs Float.MAX_VALUE et Float.MIN_VALUE dans Kotlin/JS. Auparavant, elles étaient égales au Number.MAX/MIN_VALUE de JavaScript, ou de manière équivalente, à Double.MAX/MIN_VALUE, car Float est sensiblement équivalent à Double dans Kotlin/JS. Désormais, ces constantes Float sont les mêmes pour toutes les plateformes.

maxOf() et minOf() avec vararg

Les fonctions maxOf() et minOf() de la bibliothèque standard trouvent la plus grande et la plus petite de deux valeurs. À partir de la version 1.4-M1, maxOf() et minOf() peuvent accepter un nombre variable d’arguments (vararg), ce qui vous permet de les utiliser sur n’importe quel ensemble de nombres ou autres éléments comparables.

Améliorations de la délégation de propriété

Dans Kotlin, les propriétés déléguées fonctionnent via des conventions, et non des interfaces : le type que vous voulez utiliser en tant que délégué doit définir une fonction d’opérateur plutôt que d’implémenter l’interface requise. Cela donne une certaine flexibilité (car nous ne sommes pas liés par des interfaces spécifiques), mais en pratique, il est utile d’utiliser des interfaces dans de nombreux cas.

Dans Kotlin 1.4, nous avons amélioré le fonctionnement de ces interfaces complémentaires en introduisant une nouvelle interface PropertyDelegateProvider et ReadWriteProperty hérite désormais de ReadOnlyProperty. Poursuivez votre lecture pour en savoir plus.

Expression Delegate

Les interfaces ReadWriteProperty et ReadOnlyProperty sont pratiques pour définir les délégués de propriété car votre classe personnalisée ou votre objet anonyme peut les implémenter :

À partir de la version 1.4, ReadWriteProperty hérite de ReadOnlyProperty. Cela vous donne plus de flexibilité pour travailler avec les expressions delegate. Dans notre exemple, vous pouvez maintenant passer l’appel myDelegate() chaque fois qu’un ReadOnlyProperty est attendu.

Nous voulons souligner ici que “read-only” n’équivaut pas à “non modifiable” dans Kotlin, tout comme une liste en lecture seule n’est pas une liste non modifiable. “Read-only” signifie que “cette interface fournit uniquement un accès en lecture seule à l’objet en question”.

Mise à disposition d’un delegate

En utilisant le mécanisme de mise à disposition d’un delegate, vous pouvez étendre la logique de création d’un objet “délégué”, c’est-à-dire l’objet auquel l’implémentation de la propriété est déléguée. Vous pouvez trouver les détails de son fonctionnement dans la documentation. Dans la version 1.4, pour rendre ce mécanisme un peu plus pratique, nous avons ajouté une nouvelle interface PropertyDelegateProvider. Vous pouvez l’utiliser lorsque vous ne souhaitez pas créer une classe supplémentaire et que vous préférez utiliser un objet anonyme, comme dans l’exemple ci-dessus de myDelegate().

Délégation à une autre propriété

À partir de la version 1.4, une propriété peut déléguer ses getter et setter directement à une autre propriété. Cela peut par exemple être utile lorsque vous souhaitez renommer une propriété de manière rétrocompatible : vous introduisez une nouvelle propriété, vous annotez une ancienne avec l’annotation @Deprecated et vous déléguez son implémentation.

L’optimisation pour les propriétés déléguées compilées décrite précédemment fonctionne dans ce cas. Comme l’implémentation de l’opérateur de délégation n’utilise pas les informations sur la propriété déléguée (oldName), il n’est pas nécessaire que le compilateur génère l’instance KProperty avec ces informations. À l’avenir, il sera également possible de ne pas générer d’instance KMutableProperty supplémentaire pour le délégué (newName).

Comment essayer

Toutes ses modifications seront incluses dans la preview de Kotlin 1.4-M2, mais vous pouvez déjà les essayer en ligne surplay.kotl.in, en sélectionnant la version version 1.4-M2 dans les paramètres.

Notes de pré-version

Veuillez noter que les garanties de rétrocompatibilité ne s’appliquent pas aux versions préliminaires. Les fonctionnalités et l’API peuvent être amenées à changer dans les versions ultérieures en fonction de vos retours.

Faites-nous part de vos commentaires

Nous vous remercions pour tous les rapports de bugs que vous partagez dans notre outil de suivi. Nous ferons de notre mieux pour traiter et solutionner tous les problèmes importants d’ici la sortie de la version finale.

Nous vous invitons à rejoindre le canal \#eap sur le Slack Kotlin (demandez une invitation ici) pour y poser vos questions, participer aux discussions et recevoir en avant-première les notifications sur les nouvelles versions.

Faison évoluer Kotlin ensemble !

Auteur de l’article original en anglais : Pavel Semyonov

image description

Discover more