11.5.6 : Rust



Comme Ada, Rust tente de rendre l'écriture de code bas niveau plus ergonomique que le C++ en évitant les comportements indéfinis et en facilitant la vérification du code par le compilateur. Cependant, il approche le problème sous un angle différent.

Dans sa syntaxe comme dans son jeu de fonctionnalités, Rust est avant tout un hybride entre C++ et les langages fonctionnels de la famille ML (OCaml, Haskell, etc). Il tire par exemple du premier une proximité avec la machine (distinction pile/tas, types entiers et flottants natifs, opérations mémoires atomiques et volatiles) et une implémentation similaire de l'objet et de la généricité. Et il tire par exemple des seconds un fort accent sur l'utilisation de données non modifiables, une utilisation intensive de l'inférence de type, et une intégration native des types de données algébriques (analogues à std::variant en C++ moderne, mais beaucoup plus ergonomiques).

L'approche de Rust pour la vérification de code à la compilation consiste à fournir trois garanties aux programmeurs~: sûreté mémoire (absence de pointeurs invalides), de typage (absence de données invalides) et concurrente (absence de recouvrement entre l'écriture d'une région mémoire et un accès mémoire parallèle par un autre fil d'exécution). Réunies, et en combinaison avec quelques autres choix de conception, ces garanties permettent de prouver l'absence de comportement indéfini à la compilation. Les programmes sont donc bien plus faciles à écrire et à valider.

Le langage fournit ces garanties automatiquement et avec vérification à la compilation dans de nombreux cas, et permet aux programmeurs d'étendre les capacités du langage en fournissant du code pour lesquels ces propriétés ont été prouvées manuellement, utilisant un sur-ensemble du langage de base (Unsafe Rust) possédant un pouvoir expressif et des risques d'utilisation analogues au C. L'utilisation de ce sur-ensemble, qui est rarement nécessaire en pratique, doit être signalée par le mot-clé unsafe, ce qui facilite l'audit de ces régions sensibles où les bogues sont plus probables.

Pour permettre la vérification automatique des propriétés ci-dessus, Rust impose un modèle d'accès mémoire plus restrictif que la plupart des autres langages~: toute référence doit pointer sur une région mémoire dont la validité peut être prouvée à la compilation, et il ne peut exister à un instant donné qu'une référence en lecture/écriture ou un ensemble de références en lecture seule vers une région mémoire. Ce modèle, analogue à celui des tableaux Fortran et des pointeurs restrict du C mais dont le respect est vérifié à la compilation, peut être difficile à prendre en main initialement. Mais outre les propriétés utiles ci-dessus, il permet aussi de meilleures optimisations par le compilateur.

Contrairement à Ada, Rust offre une excellente interopérabilité avec le C et les bibliothèques qui fournissent des interfaces C, via son sur-ensemble unsafe. En termes de niveau d'abstraction, Rust se comporte essentiellement comme un cousin de C++ avec certaines restrictions visant à rendre moins périlleuse l'utilisation courante (ex~: pas d'utilisation de pointeurs bruts sans unsafe), certaines évolutions nécessaires qui peinent à émerger en C++ du fait de l'âge et de l'inertie du langage (ex~: système de modules, types et fonctions génériques qui fixent des bornes strictes sur ce qu'ils acceptent en argument, mécanisme d'itération ergonomique, etc), et certaines idées nouvelles pour la communauté bas niveau qui ouvrent la voie à de nouveaux styles de programmation (ex~: types de données algébriques).

Comme C++ également, Rust est un langage relativement difficile à apprendre et plutôt destiné aux experts qui souhaitent consacrer un effort conséquent à son apprentissage. Ce défaut semble indissociable de la volonté de concilier contrôle précis de la machine et grand pouvoir expressif dans un même langage de programmation.

À l'heure actuelle, Rust est probablement le concurrent le plus sérieux à C++ pour les nouveaux développements ou réécritures où l'on est prêt à lui pardonner une certaine immaturité (fonctionnalités avancées du langage encore en cours de développement, faible nombre de bibliothèques natives), en échange de quoi on gagne en confort d'utilisation, vérification automatique du code, et plus généralement en productivité.

Rust est généralement compilé statiquement vers des binaires natifs, bien qu'il existe des prototypes de systèmes permettant de l'interpréter à la manière de ROOT.