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 :
- Modifications de l’API existante comme la mise à jour des signatures et l’introduction de nouvelles constantes
- Ajout de fonctions dans la bibliothèque commune
- Nouvelles fonctions pour les tableaux et les collections
- Améliorations de la délégation de propriété
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()
etreduceIndexedOrNull()
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()
etrunningReduce()
ont été ajoutés comme synonymes descan()
etscanReduce()
. Ces noms sont plus cohérents avec les fonctions connexesfold()
etreduce()
. À l’avenir,scan()
sera disponible avecrunningFold()
car c’est un nom couramment utilisé pour cette opération. Cependant, la fonction expérimentalescanReduce()
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