Developpez.com

Le Club des Développeurs et IT Pro

Mozilla annonce la disponibilité de Rust 1.16

Qui s'accompagne de la sous-commande cargo check

Le 2017-03-17 20:49:39, par Stéphane le calme, Chroniqueur Actualités
L’équipe responsable du développement de Rust a annoncé la disponibilité de la version stable 1.16. L’un des ajouts majeurs apportés au langage de programmation est la sous-commande cargo check laquelle, selon l’équipe, devrait vous aider à accélérer votre flux de travail dans bien des cas.

Que fait-elle exactement ? Avant d’y parvenir, il faut d’abord s’intéresser à la façon dont rustc compile votre code. Il existe de nombreuses étapes distinctes par lesquelles le compilateur passe entre votre code source et la production du binaire final. Pour observer ces étapes, et surtout combien de temps et de mémoire elles prennent, vous pouvez lancer la commande -Z time-passes à un compilateur nightly.

rustc .\hello.rs -Z time-passes
time: 0.003; rss: 16MB parsing
time: 0.000; rss: 16MB recursion limit
time: 0.000; rss: 16MB crate injection
time: 0.000; rss: 16MB plugin loading
time: 0.000; rss: 16MB plugin registration
time: 0.049; rss: 34MB expansion
<snip>

Comme vous pouvez le constater avec cet exemple, il y a plusieurs étapes. Cependant, nous pouvons les regrouper en deux grandes catégories :
  • tout d'abord, rustc effectue toutes ses vérifications de sécurité, il s'assure que votre syntaxe est correcte, etc. ;
  • ensuite, une fois qu'il a terminé ses routines de vérification, il produit le code binaire réel que vous finissez par exécuter.

Il s’avère que cette seconde grande étape prend beaucoup de temps qui n'est pas souvent nécessaire. Autrement dit, lorsque vous travaillez sur un code Rust, de nombreux développeurs vont procéder comme suit :
  1. Écrire une portion de code ;
  2. Exécuter cargo build pour s'assurer qu'il n’y a pas d’erreurs de compilation ;
  3. Répéter les étapes 1 et 2 si nécessaire ;
  4. Exécutez cargo test pour s'assurer qu’il n’y pas d’erreurs dans les tests ;
  5. Retour à l’étape numéro 1.

En réalité, une fois rendu à l’étape 2, il n’est pas vraiment question de lancer l’exécution de votre code : il s’agit d’avoir un feedback du compilateur, mais pas dans l’optique d’exécuter le binaire. C’est dans ce cas d’utilisation que cargo check intervient : il exécute toutes les vérifications du compilateur, mais ne produit pas le binaire final.

Alors concrètement de quel pourcentage de vitesse les développeurs vont-ils bénéficier ? Les ingénieurs indiquent que, comme c'est le cas avec les questions de performance, la réponse est « ça dépend ». Toutefois, ils ont fourni un benchmark permettant de comparer des gains de vitesse sur différentes catégories.

Fonctionnalités de cargo

En plus de cargo check, Cargo et crates.io ont été retravaillés. Par exemple, cargo build et cargo doc supportent désormais le flag --all pour construire et documenter tous les “crate” dans votre espace de travail en une commande.

Pour rappel, Rust a deux termes distincts qui se rapportent au système de module : 'crate' et 'module'. Un crate est synonyme d'une « bibliothèque » ou d'un « paquet » dans d'autres langages. Par conséquent, "Cargo”, en tant que nom de l'outil de gestion de paquets de Rust, permet de diffuser les “crate” à d’autres avec Cargo. Les “crate” peuvent produire un exécutable ou une bibliothèque, selon le projet.

Autres améliorations

Afin de supporter cargo check, rustc fournit désormais un nouveau type de fichier : .rmeta. Ce fichier contient uniquement des métadonnées sur un “crate” en particulier. cargo check en a besoin pour vos dépendances afin de laisser le compilateur vérifier par exemple les types.

Source : blog Rust
  Discussion forum
45 commentaires
  • Songbird
    Membre expert


    Je ne doutes pas que je finirais par en faire,
    mais aujourd'hui à cet instant, la chose n'est pas évidente pour moi
    et je préfère encore me tourner vers d'autres langages
    partageant certains points commun avec celui ci.
    Qu'est-ce qui te paraît peu évident ? Tes questions et remarques sont les bienvenues.

    Concernant la syntaxe, c'est précisément ce qui me donne envie d'étudier Rust (si l'on ne parle que d'elle), car la syntaxe me semble moins... éparpillée que le C++. Cela reste très personnel, bien entendu.
    D'ailleurs, si quelque chose te rebute dans la syntaxe, des ressources existent pour expliquer littéralement ce que signifie telle ou telle expression.

    Très bonne journée !
  • mh-cbon
    Membre extrêmement actif
    Rust c'est tout de même plusieurs choses, amha.

    Un langage pour répondre aux problèmes de ces prédécesseurs.
    Un toolset autour du langage pour vivre avec.
    Un esprit définitivement progressiste et tourné vers l'avenir.

    De cet ensemble, je suis très satisfait,
    c'est un changement appréciable car il est plus proche des utilisateurs,
    en comparaison, pendant longtemps les avancées que l'on pouvait lire à propos des langages
    concernaient des questions très théorique de la théorie des langages (preuves formelles etc)
    qui finalement aboutissaient à peu de changement concret/applicable pour l'utilisateur final lambda.

    J'apprécie beaucoup cela, pour autant est ce que j'aime ce langage,
    bein pas trop en fait,
    comme tout le monde, j'aime bien sa théorie et sa mise en pratique,
    mmmmmeeeeehhhhhh
    la syntaxe est bien trop complexe pour mon goût personnel.

    Je ne doutes pas que je finirais par en faire,
    mais aujourd'hui à cet instant, la chose n'est pas évidente pour moi
    et je préfère encore me tourner vers d'autres langages
    partageant certains points commun avec celui ci.
  • imperio
    Membre émérite
    la syntaxe est bien trop complexe pour mon goût personnel.
    Ah ? Voilà qui est intéressant ! Venant des langages C/C++, j'ai trouvé la syntaxe de rust nettement plus simple. De quel(s) langage(s) viens-tu du coup ?
  • mothsART
    Membre régulier
    Mh-cbon : ton approche top => bottom est bonne : beaucoup ne font pas l'effort et du coup progresse peu à mon sens.
    Le passage à un typage fort est douloureux mais au final nécessaire car le gain est juste énorme : tu évites une paire de bug à l’exécution, le code est plus cohérent, t'as de meilleurs perfs etc.

    Tu mets C et C++ dans le panier des vieux langages mais tu remarqueras que Go ne les remplace pas vraiment car il utilise un Garbage collector et une VM.
    Pour moi, Go est un Java bis avec une syntaxe minimaliste, des gros avantages sur la programmation concurrente et des temps de compilation plus court.
    Bref, rien de bien novateur à mon sens.

    La réalité est que C et C++ sont pour l'instant encore indétrônable dans tous les domaines ou les perfs et la gestion de la mémoire sont critiques.
    Rust étant plus ambitieux et par conséquent plus complexe est un réel candidat pour les remplacer.

    Je dirais, pour ma part que le cap à passer pour Rust n'était pas vraiment la syntaxe (que je trouve élégante et intuitive) mais plus le borrowing. (et dans une moindre mesure les macros et closures)

    Mais, comme tous les langages, il a des zones implicites qui nécessite apprentissage.
    Ton exemple et ton incompréhension proviennent de là :

    * la variable "f" et "let mut f" : f est dans un premier temps immutable : si le match réussi (passe par le Ok), cette variable est écrasé par le résultat et est converti en une variable mutable.
    * le type Result est un peu particulier : il attend soit un objet succès ("Ok" avec le résultat (ici typé en String car on désire récupérer le contenu du fichier mais ça pourrais être n'importe quoi d'autre dans un autre contexte) ou un objet d'échec ("Err".
    * le premier match (qui vérifie l'accès en lecture du fichier) a un retour explicite qui précise que si il détecte une erreur, il sort directement de la fonction (et par conséquent la variable mutable f n'est pas alimenté, la variable s n'est pas créé et le dernier match non executé.
    * let permet de déclarer une variable, je ne vois pas trop ce qui te choques. (tu remplaces "var" par "let" dans ton passage de Go à Rust ou de NodeJS à Rust)
    * en rust si la dernière ligne d'une fonction ne se termine pas par ";", on retourne implicitement le résultat.
    C'est ce qui se passe dans le dernier match.
    * s n'est pas déclaré 2 fois, elle est passé par référence dans la fonction "read_to_string".
    * read_username_from_file renvoi une valeur qui peut parfaitement être mutable ou non selon la déclaration de ta variable de récupération :
    Code :
    1
    2
    3
    4
    let username_immutable = read_username_from_file();
    // ou
    let mut username_mutable = read_username_from_file();
  • Uther
    Expert éminent sénior
    Envoyé par mh-cbon 
    Je ne vois pas où est construit le retour Result<...>.

    Result est un cas particulier vu que comme c'est un élément central du langage, ses variant OK et Err sont inclus dans le prélude, ce qui fait que l'on peut les utiliser directement. Comme le type Result est utilisé partout, n'importe qui avec un minimum d'expérience dans le langage reconnais ça du premier abord.

    Cependant, si tu tient à ce que ce soit clair que Ok et Err sont des variants du type énuméré Result, tu peux faire :
    Code Rust :
    1
    2
    3
    4
        let mut f = match f { 
            Result::Ok(file) => file, 
            Result::Err(e) => return Result::Err(e), 
        };
  • Songbird
    Membre expert


    Tout comme les variantes de l'enum Option<T>: Some(T) et None sont parfaitement comprises par le compilateur.

    Sans expliciter la provenance des variantes ça donne:

    Code Rust :
    1
    2
    3
    4
    5
    6
    7
    8
    fn main() { 
        let foo = Some("Hello there!".to_owned()); 
        let bar = match foo{ 
            Some(content) => content, 
            None => "Nothing, here.".to_owned(), 
        }; 
        println!("bar={}", &bar); 
    }

    Ce sont de petites subtilités, mais vraiment rien d'insurmontable. Ce ne sont pas des ressources "magiques", juste des raccourcis.
  • tralloc
    Membre averti
    @mh-cbon
    Eh bien moi c'est la deuxième fois que je me penche sur ce language.la première fois je l'ai trouvé trop complexe moi aussi.
    Rien à voir avec les typages forts parce que je fais du JEE du C. Ni les typages faibles, car je ne suis pas trop mauvais en python.
    Eh bien pour une deuxième fois, je commence à l'apprécier, et je crois qu'il vaut vraiment le coup.

    La syntaxe est une chose, lorsqu'on a commencé à la comprendre il faut ensuite l'adopter. Une fois ce cap passé on peut profiter de sa richesse.
  • Kennel sébastien
    Membre averti
    Bonjour tralloc,

    C'est super de chercher à aider les autres :-).

    Je voulais juste me permettre de te signaler un point :-p :
    Tu as écrit « Ni les typages faibles, car je ne suis pas trop mauvais en python », or Python a un typage fort, en effet tu confonds typage statique et dynamique mais les trois langages ont des typages fort.

    Des langages qui auraient des typages faibles sont par exemple : PHP, Javascript ou Ring.

    Code :
    print(5 + "5")
    Ne travaille pas en Python, mais sous Ring avec :
    Code :
    See 5 + "5"
    Tu obtiens le résultat 10 !

    Rust a en fait un typage qui est inféré comme Go, Crystal, Swift…, c'est-à-dire que tu peux le rendre statique ou le laisser chercher le type pour toi alors que tu pourrais pas le faire en Python, en Python c'est lui qui cherche pour toi, il n'y a pas de déclaration de type.

    Enfin pour ceux qui trouvent trop difficile Rust, peut-être vous tournez sur Go et revenir après sur Rust…
  • joublie
    Membre confirmé
    [B]cargo check[/C]

    " Alors concrètement de quel pourcentage de vitesse les développeurs vont-ils bénéficier ? " C'est assez mal rédigé, non ?
  • Uther
    Expert éminent sénior
    Oui, c'est un traduction assez moyenne de l'article.

    Niveau vitesse ça dépend du type de code, certains type de code sont plus couteux que d'autres a compiler. Sur mes programmes, la différence par rapport entre une vérification seule et une compilation (sans optimisation) est de l'ordre de 3 à 6 fois plus rapide.

    Après "make check" ne sert que a vérifier s'il y a des erreur de compilation. Si on veut tester, il faudra quand même faire une construction complète après.