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 !

L'équipe de développement de Rust présente son plan pour Rust 2021 qui correspond à la troisième édition du langage
Avec une amélioration significative à la façon dont Rust se comporte en pratique

Le , par Bill Fassinou

45PARTAGES

15  0 
L'équipe de Rust a annoncé mardi qu'elle publiera en octobre Rust 2021. Les détails de son plan indiquent que Rust 2021 contient un certain nombre de petits changements qui devraient apporter une amélioration significative à la façon dont Rust se comporte en pratique. Lors de la première annonce en septembre 2020, l'équipe avait déclaré qu'il est prévu que la nouvelle édition ait une portée beaucoup plus limitée que celle de Rust 2018. Elle devrait inclure quelques ajustements mineurs pour améliorer la convivialité du langage et la promotion de différents idiomes d'édition afin qu'ils soient “refusés par défaut”.

Qu'est-ce qu'une édition et en quoi est-elle importante ?

Selon l'équipe principale du langage, la sortie de Rust 1.0 a établi la "stabilité sans stagnation" comme un livrable essentiel de Rust. Depuis la version 1.0, la règle pour Rust a été qu'une fois qu'une fonctionnalité a été publiée dans la version stable, l'équipe s'engage à supporter cette fonctionnalité pour toutes les futures versions. Cependant, il est parfois utile de pouvoir apporter de petites modifications qui ne sont pas rétrocompatibles. L'exemple le plus évident est l'introduction d'un nouveau mot-clé, qui invaliderait les variables portant le même nom. Voici une illustration, selon l'équipe.



La première version de Rust n'avait pas les mots-clés async et await. Le changement soudain de ces mots en mots-clés dans une version ultérieure aurait cassé du code comme let async= 1;. Ainsi, les éditions sont le mécanisme par lequel l'équipe résout ce problème. Lorsqu'elle souhaite publier une fonctionnalité qui serait autrement incompatible avec le passé, elle le fait dans le cadre d'une nouvelle édition de Rust. Les éditions sont opt-in, et donc les crates existants ne voient pas ces changements jusqu'à ce qu'ils migrent explicitement vers la nouvelle édition.

Cela signifie que même la dernière version de Rust ne traitera toujours pas async comme un mot-clé, à moins que l'édition 2018 ou ultérieure ne soit choisie. Ce choix est fait par le crate dans le cadre de son Cargo.toml. Les nouveaux crates créés par cargo new sont toujours configurés pour utiliser la dernière édition stable.

Éditions, changements, rétrocompatibilité et migration

Selon l'équipe, les éditions ne divisent pas l'écosystème. « La règle la plus importante pour les éditions est que les crates d'une édition peuvent interagir de manière transparente avec les crates compilés dans d'autres éditions », explique-t-elle. Cela garantirait que la décision de migrer vers une édition plus récente est une décision "privée" que le crate peut prendre sans affecter les autres. L'exigence d'interopérabilité des crates implique donc certaines limites sur les types de changements qu'elle peut faire dans une édition. En général, les changements qui se produisent dans une édition ont tendance à être "superficiels".

« Tout le code Rust, quelle que soit l'édition, est finalement compilé dans la même représentation interne au sein du compilateur », note-t-elle. En outre, elle ajoute que la migration des éditions est facile et largement automatisée. « Notre objectif est de faciliter la mise à niveau des caisses vers une nouvelle édition », a-t-elle déclaré. « Lorsque nous publions une nouvelle édition, nous fournissons également des outils pour automatiser la migration. Il apporte à votre code les modifications mineures nécessaires pour le rendre compatible avec la nouvelle édition », a ajouté l'équipe.

Par exemple, selon elle, lors de la migration vers Rust 2018, il modifie tout ce qui est nommé async pour utiliser la syntaxe d'identifiant brut équivalente : r#async. Elle estime néanmoins que les migrations automatisées ne sont pas nécessairement parfaites : il peut y avoir des cas particuliers où des modifications manuelles sont encore nécessaires. L'outil s'efforce d'éviter les changements sémantiques qui pourraient affecter la correction ou les performances du code. En plus de l'outillage, elle maintient également un guide de migration d'édition qui couvre les changements qui font partie d'une édition.

Ce guide décrit le changement et indique où les gens peuvent en apprendre davantage à son sujet. Il couvre également tous les cas particuliers ou les détails que les gens doivent connaître. Le guide sert à la fois d'aperçu de l'édition, mais aussi de référence pour le dépannage rapide si les gens rencontrent des problèmes avec l'outillage automatisé.

Quels sont les changements prévus pour Rust 2021 ?

L'équipe a déclaré qu'au cours des derniers mois, le groupe de travail Rust 2021 a examiné un certain nombre de propositions concernant les éléments à inclure dans la nouvelle édition. Elle présente désormais la liste finale des changements retenus pour cette édition. Chaque fonctionnalité devait répondre à deux critères pour faire partie de cette liste. Premièrement, elle devait être approuvée par la ou les équipes Rust concernées. Deuxièmement, leur mise en œuvre devait être suffisamment avancée pour que l'équipe principale ait la certitude qu'elles sont terminées à temps pour les jalons prévus.

Ajouts a prelude

Prelude de la bibliothèque standard est le module contenant tout ce qui est automatiquement importé dans chaque module. Il contient des éléments couramment utilisés tels que Option, Vec, drop et Clone. L'équipe a expliqué que le compilateur Rust donne la priorité aux éléments importés manuellement sur ceux du prelude, afin de s'assurer que les ajouts au prelude ne cassent pas le code existant. Prenez un exemple où vous avez un crate ou un module appelé example contenant un pub struct Option.

Dans ce cas, use example::*; fera en sorte que Option se réfère sans ambiguïté à celui de example ; et non à celui de la bibliothèque standard. Cependant, l'ajout d'un trait au prelude peut casser le code existant d'une manière subtile. Un appel à x.try_into() utilisant un trait MyTryInto peut devenir ambigu et ne pas compiler si TryInto de std est également importé, puisqu'il fournit une méthode avec le même nom.

C'est la raison pour laquelle l'équipe n'a pas encore ajouté TryInto au prelude, car beaucoup de code serait cassé de cette façon. Comme solution, Rust 2021 utilisera un nouveau prelude. Il est identique à l'actuel, à l'exception de trois nouveaux ajouts :

  • std::convert::TryInto ;
  • std::convert::TryFrom ;
  • std::iter::FromIterator.

Résolveur de fonctionnalités par défaut de Cargo

Depuis la version 1.51.0 de Rust, Cargo prend en charge un nouveau résolveur de fonctionnalités qui peut être activé avec resolver= "2" dans Cargo.toml. À partir de Rust 2021, ce sera la valeur par défaut. En d'autres termes, écrire edition= "2021" dans Cargo.toml impliquera resolver= "2". Le nouveau résolveur de fonctionnalités ne fusionne plus toutes les fonctionnalités demandées pour les crates qui sont dépendants de plusieurs façons.

IntoIterator pour les tableaux

Jusqu'à Rust 1.53, seules les références aux tableaux implémentent IntoIterator. Cela signifie que vous pouvez itérer sur &[1, 2, 3] et &mut [1, 2, 3], mais pas sur [1, 2, 3] directement. Selon l'équipe, il s'agit d'un problème de longue date, mais la solution n'est pas aussi simple qu'il paraît. L'ajout de l'implémentation du trait casserait le code existant. array.into_iter() compile déjà aujourd'hui parce qu'il appelle implicitement (&array).into_iter() en raison du fonctionnement de la syntaxe d'appel de méthode.

L'ajout de l'implémentation du trait en changerait la signification. Habituellement, l'équipe qualifie ce type de rupture de "mineure" et acceptable. Mais dans ce cas, il y a trop de code qui serait cassé par cela. Selon elle, il a été suggéré à plusieurs reprises de n'implémenter IntoIterator que pour les tableaux en Rust 2021. Cependant, cela n'est tout simplement pas possible. Vous ne pouvez pas avoir une implémentation de trait existant dans une édition et pas dans une autre, puisque les éditions peuvent être mélangées.

Au lieu de cela, l'équipe a décidé d'ajouter l'implémentation de trait dans toutes les éditions (à partir de Rust 1.53.0), mais d'ajouter un petit hack pour éviter la rupture jusqu'à Rust 2021. Dans le code Rust 2015 et 2018, le compilateur résoudra toujours array.into_iter() en (&array).into_iter() comme avant, comme si l'implémentation du trait n'existait pas. Cela s'applique uniquement à la syntaxe d'appel de la méthode .into_iter(). Cela n'affecte pas les autres syntaxes telles que for e in [1, 2, 3], iter.zip([1, 2, 3]) ou IntoIterator::into_iter([1, 2, 3]).

Celles-ci commenceront à fonctionner dans toutes les éditions. Selon l'équipe, bien qu'il soit dommage que cela nécessite un petit hack pour éviter la casse, elle se dit heureuse de la façon dont cette solution maintient la différence entre les éditions à un minimum absolu. Comme le hack n'est présent que dans les anciennes éditions, il n'y a pas de complexité supplémentaire dans la nouvelle édition.

Capture disjointe dans les closures

Les closures capturent automatiquement tout ce à quoi vous faites référence à l'intérieur de leur corps. Par exemple, || a + 1 capture automatiquement une référence à a à partir du contexte environnant. Actuellement, cela s'applique à des structures entières, même si elles n'utilisent qu'un seul champ. Par exemple, || a.x + 1 capture une référence à a et pas seulement à a.x. Selon l'équipe, dans certaines situations, cela pose un problème. Lorsqu'un champ de la structure est déjà emprunté ou déplacé, les autres champs ne peuvent plus être utilisés dans une fermeture,

Cela aura pour effet de capturer la structure entière, qui n'est plus disponible. À partir de Rust 2021, les fermetures ne captureront que les champs qu'elles utilisent. Ainsi, l'exemple ci-dessus compilera bien en Rust 2021. Ce nouveau comportement n'est activé que dans la nouvelle édition, car il peut changer l'ordre dans lequel les champs sont supprimés. Comme pour tous les changements d'édition, une migration automatique est disponible, qui mettra à jour vos closures pour lesquelles cela est important. Il peut insérer let _ = &a; à l'intérieur de la closure pour forcer la capture de la structure entière comme avant.

Cohérence de la macro panic

La macro panic!() est l'une des macros les plus connues de Rust. Cependant, l'équipe estime qu'elle présente quelques surprises subtiles qu'elle ne peut pas modifier pour des raisons de compatibilité ascendante. La macro panic!() n'utilise le formatage des chaînes que lorsqu'elle est invoquée avec plus d'un argument. Lorsqu'elle est invoquée avec un seul argument, elle ne regarde même pas cet argument. (Elle accepte même les non-chaînes de caractères comme panic!(123), ce qui est peu courant et rarement utile). Ceci serait particulièrement un problème une fois que les arguments de format implicites seront stabilisés.

Cette fonctionnalité fera de println!("hello {name}" un raccourci pour println!("hello {}", name). Cependant, panic!("hello {name}" ne fonctionnerait pas comme prévu, puisque panic!() ne traite pas un argument unique comme chaîne de format. Pour éviter cette situation confuse, Rust 2021 propose une macro panic!() plus cohérente. La nouvelle macro panic!() n'acceptera plus les expressions arbitraires comme seul argument. Tout comme println!(), elle traitera toujours le premier argument comme une chaîne de format.

Puisque panic!() n'acceptera plus de charges utiles arbitraires, panic_any() sera le seul moyen d'utiliser panic!() avec autre chose qu'une chaîne formatée. De plus, core::panic!() et std::panic!() seront identiques dans Rust 2021. Actuellement, il y a quelques différences historiques entre ces deux-là, qui peuvent être perceptibles lors de l'activation ou de la désactivation de #![no_std].

Réserver la syntaxe

Pour faire de la place pour une nouvelle syntaxe dans le futur, l'équipe a décidé de réserver la syntaxe pour les identificateurs et les littéraux préfixés : prefix#identifier, prefix "string", prefix "c", et prefix#123, où prefix peut être n'importe quel identificateur. (Sauf ceux qui ont déjà une signification, comme b'...' et r"..."). Il s'agit d'un changement de rupture, puisque les macros peuvent actuellement accepter hello"world", qu'elles verront comme deux jetons séparés : hello et "world".

La correction (automatique) est cependant simple. Il suffit d'insérer un espace : hello "world". En dehors de la transformation de ces erreurs en erreurs de tokénisation, la RFC n'attache pas encore de signification à un quelconque préfixe. L'attribution d'une signification à des préfixes spécifiques est laissée aux propositions futures, qui, grâce à la réservation de ces préfixes maintenant, ne seront pas des changements de rupture. Voici quelques nouveaux préfixes que vous pourriez voir à l'avenir :

  • f"" comme raccourci pour une chaîne de format. Par exemple, f"hello {name}" comme raccourci de l'invocation format_args!() équivalente ;
  • c"" ou z"" pour les chaînes C à terminaison nulle ;
  • k#keyword pour permettre l'écriture de mots-clés qui n'existent pas encore dans l'édition actuelle. Par exemple, bien que async ne soit pas un mot-clé dans l'édition 2015, ce préfixe aurait permis d'accepter k#async comme alternative dans l'édition 2015 en attendant que l'édition 2018 réserve async comme mot-clé.

Promotion de deux avertissements en erreurs graves

Deux lints existantes deviennent des hard errors dans Rust 2021. Ces lints resteront des avertissements dans les anciennes éditions.

  • bare-trait-objects : l'utilisation du mot-clé dyn pour identifier les objets traits sera obligatoire dans Rust 2021 ;
  • ellipsis-inclusive-range-patterns : la syntaxe dépréciée ... pour les modèles de plage inclusive n'est plus acceptée dans Rust 2021. Elle a été remplacée par ..=, qui est cohérente avec les expressions.

Les motifs dans macro_rules

À partir de Rust 1.53.0, les motifs sont étendus pour supporter les | imbriqués n'importe où dans le motif. Cela vous permet d'écrire Some(1 | 2) au lieu de Some(1) | Some(2). Comme cela n'était tout simplement pas autorisé auparavant, il ne s'agit pas d'un changement radical. Toutefois, ce changement affecte également les macros macro_rules. Ces macros peuvent accepter des motifs utilisant le spécificateur de fragment :pat. Actuellement, :pat ne correspond pas à |, car avant Rust 1.53, tous les motifs (à tous les niveaux imbriqués) ne pouvaient pas contenir un |.

Les macros qui acceptent des motifs comme A | B, comme matches!() utilisent quelque chose comme $($_:pat)|+. L'équipe a déclaré que, comme elle ne veut pas casser les macros existantes, elle n’a pas modifié la signification de :pat dans Rust 1.53.0 pour inclure |. Au lieu de cela, elle fera ce changement dans le cadre de Rust 2021.

Dans la nouvelle édition, le spécificateur de fragment :pat correspondra à A | B. Comme il arrive parfois que l'on souhaite faire correspondre une seule variante de motif sans |, le fragment spécifié :pat_param a été ajouté pour conserver l'ancien comportement. Le nom fait référence à son principal cas d'utilisation : un motif dans un paramètre closure.

Quelles sont les prochaines étapes ?

L'équipe prévoit de fusionner ces changements et de les tester entièrement d'ici septembre, afin de s'assurer que l'édition 2021 sera intégrée à Rust 1.56.0. Rust 1.56.0 sera alors en version bêta pendant six semaines, après quoi il sera publié en version stable le 21 octobre. Cependant, notez que Rust est un projet géré par des bénévoles, il peut donc arriver que le calendrier soit bouleversé.

« Nous donnons la priorité au bien-être personnel de tous ceux qui travaillent sur Rust plutôt qu'aux délais et aux attentes que nous avons pu fixer. Cela peut signifier retarder l'édition d'une version si nécessaire, ou abandonner une fonctionnalité qui s'avère trop difficile ou trop stressante pour être terminée à temps. Cela dit, nous sommes dans les temps et beaucoup de problèmes difficiles sont déjà résolus, grâce à toutes les personnes qui contribuent à Rust 2021 », a-t-elle déclaré.

Source : Plan de l'édition Rust 2021

Et vous ?

Que pensez-vous des changements intervenus dans Rust 2021 ?

Voir aussi

Feuille de route de Rust pour 2021 : l'équipe souhaite étendre la communauté du langage et pourrait travailler sur une éventuelle édition de Rust 2021

Rust 1.51 est disponible avec Resolver, une nouvelle fonctionnalité pour Cargo et l'implémentation MVP des const generics

Rust 1.50.0 est disponible et s'accompagne de l'indexation de tableau générique Const, ainsi que des affectations sécurisées aux champs d'union ManuallyDrop<T>

Rust 1.49.0 est disponible avec l'amélioration des supports de Linux ARM 64 bits, MacOS et Windows ARM 64 bits

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