IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langages de programmation Discussion :

Zig, le langage de programmation compilé, inspiré de Rust, serait plus sûr et plus rapide que Rust


Sujet :

Langages de programmation

  1. #1
    Chroniqueur Actualités
    Avatar de Bruno
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    Mai 2019
    Messages
    1 852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Rédacteur technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Mai 2019
    Messages : 1 852
    Points : 36 402
    Points
    36 402
    Par défaut Zig, le langage de programmation compilé, inspiré de Rust, serait plus sûr et plus rapide que Rust
    Zig est un langage de programmation polyvalent et serait une chaîne d'outils permettant de maintenir des logiciels robustes,
    optimaux et réutilisables

    Zig est un langage de programmation relativement jeune pour la programmation de bas niveau. Peut-être pas aussi bas niveau que l'assembleur, mais certainement aussi bas niveau que C ou C++. Il permet de se concentrer sur le débogage de l’application plutôt que sur ses connaissances en langage de programmation. « Je suis habituellement très sceptique à l'égard des nouveaux langages, alors j'ai naturellement voulu essayer Zig. Mais après avoir joué et construit quelques petits projets avec, je dois dire que j'ai vraiment apprécié de coder en Zig », déclare Serge Zaitsev, programmeur informatique, au sujet de Zig.

    La Zig Software Foundation est une société à but non lucratif fondée en 2020 par Andrew Kelley, le créateur de Zig, dans le but de soutenir le développement du langage. Actuellement, la ZSF est en mesure d'offrir du travail rémunéré à des tarifs compétitifs à un petit nombre de contributeurs principaux. Nous espérons être en mesure d'étendre cette offre à un plus grand nombre de contributeurs principaux à l'avenir.

    Nom : ZigB.jpg
Affichages : 32117
Taille : 7,7 Ko

    Zig est un langage de programmation open source conçu par Andrew Kelley pour garantir les performances telles que la robustesse et la maintenabilité. Andrew a annoncé dans une courte introduction au langage Zig qu’il l’a créé dans le but de concurrencer voire remplacer à l’avenir le redoutable langage C dans le cadre de la programmation système. Ainsi, il dit avoir bâti Zig sur quatre principaux aspects afin qu’il soit un langage de programmation pragmatique, optimal, un coffre-fort en matière de sécurité et un langage le plus lisible possible.

    « Je ne suis pas si ambitieux et mon objectif est de créer un nouveau langage de programmation qui sera plus pragmatique que le C. C'est comme essayer d'être plus diabolique que le diable lui-même », a écrit Andrew en introduction à la présentation du langage Zig. Lorsqu’il parle de langage plus pragmatique, il fait allusion au fait « que tout ce qui compte à la fin, c’est de savoir si le langage vous a aidé à faire ce que vous tentiez de faire et d’une manière plus simple que les autres langages ».

    La Zig Software Foundation présente le langage Zig comme un langage simple qui permet de se concentrer sur le débogage de votre application plutôt que sur celui de vos connaissances en langage de programmation.

    • Pas de flux de contrôle caché ;
    • Pas d'allocations de mémoire cachées ;
    • Pas de préprocesseur, pas de macros.

    Avec sa nouvelle approche de la métaprogrammation basée sur l'exécution du code à la compilation et l'évaluation passive, il est possible d’appeler n'importe quelle fonction au moment de la compilation, de manipuler les types comme des valeurs sans surcharge d'exécution.

    Il est également possible d’utiliser Zig en tant que compilateur C/C++ à dépendance zéro et à intégration immédiate, qui prend en charge la compilation croisée dès la sortie, d’exploiter zig build pour créer un environnement de développement cohérent sur toutes les plateformes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    const std = @import("std");
    const json = std.json;
    const payload =
        \\{
        \\    "vals": {
        \\        "testing": 1,
        \\        "production": 42
        \\    },
        \\    "uptime": 9999
        \\}
    ;
    const Config = struct {
        vals: struct { testing: u8, production: u8 },
        uptime: u64,
    };
    const config = x: {
        var stream = json.TokenStream.init(payload);
        const res = json.parse(Config, &stream, .{});
        // Assert no error can occur since we are
        // parsing this JSON at comptime!
        break :x res catch unreachable;
    };
    pub fn main() !void {
        if (config.vals.production > 50) {
            @compileError("only up to 50 supported");
        }
        std.log.info("up={d}", .{config.uptime});
    }

    Zig ressemblerait beaucoup au bon côté du C, lorsque le langage est simple et petit, que les programmes qui en résultent restent minuscules et rapides, et que le codage ressemble à du « codage » et non à de « l'ingénierie » ou de « l'architecture ». Zig reste plaisant. Selon Serge Zaitsev, l'une des raisons pour lesquelles Zig est plaisant, c'est que le langage lui-même est petit. On peut explorer la syntaxe complète et les constructions de base du langage en moins d'une heure. Par exemple, voici une tentative d'introduire Zig avec quelques lignes de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // Single-line comments start with "//", documentation comments start with "///"
    
    const x: i32 = 42; // immutable int32 value that can not be changed
    var y: u32 = 5;    // mutable unsigned int32 variable
    var z = y; // type can be omitted if it can be inferred from the value
    
    // There is no "int" type, all integers have fixed width.
    // Same about floats, there are f16, f32, f64 and f128.
    // For indices, "intptr_t" or "size_t" types use "isize" or "usize".
    
    // All function parameters are immutable as if they are passed-by-value.
    fn add_two_ints(a: i32, b: i32) i32 {
    	if (a == 0) { // if statement looks like C
    		return b;
    	}
    	return a+b;
    }
    
    // Arrays have fixed length, here numbers.len == 5
    const numbers = [_]i32{ 0, 1, 3, 5, 7 };
    // String literals are arrays of []u8
    const hello = "hello";
    // Arrays can be initialised with repeating values using ** operator
    const ten_zero_bytes = [_]u8{0} ** 10;
    // Arrays may contain a sentinel value at the end, here array.len == 4 and array[4] == 0.
    const array = [_:0]u8 {1, 2, 3, 4};
    // Slices are pointers to array data with associated length. The difference between
    // arrays and slices is that array's length is known at compile time, while slice
    // length is only known at runtime. Like arrays, slices also perform bounds checking.
    const full_slice = numbers[0..]; // points at &numbers[0] and has length of 5
    const short_slice = numbers[1..3]; // points at &numbers[1] and has length of 2
    
    fn count_nonzero(a: []const i32) i32 {
    	var count: i32 = 0;
    	for (items) |value| { // "for" works only on arrays and slices, use "while" for generic loops.
    		if (value == 0) {
    			continue;
    		}
    		count += 1; // there is no increment operator, but there are shortcuts for +=, *=, >>= etc.
    	}
    }
    
    pub fn main() void { // main() is a special entry point to your program
    	var eight = add_two_ints(3, 5);
    	var nonzeros = count_nonzero(full_slice);

    Zig est en concurrence avec C au lieu d'en dépendre

    La bibliothèque standard Zig s'intègre à libc, mais n'en dépend pas. Voici Hello World :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const std = @import("std");
    
    pub fn main() void {
        std.debug.print("Hello, world!\n", .{});
    }

    $ zig build-exe hello.zig
    $ ./hello
    Hello, world!


    Lorsqu'il est compilé avec -O ReleaseSmall, sans les symboles de débogage, en mode single-threaded, il produit un exécutable statique de 9,8 KiB pour la cible x86_64-linux :

    $ zig build-exe hello.zig -O ReleaseSmall --strip --single-threaded
    $ wc -c hello
    9944 hello
    $ ldd hello
    not a dynamic executable


    Une version Windows est encore plus petite, avec 4096 octets :

    $ zig build-exe hello.zig -O ReleaseSmall --strip --single-threaded -target x86_64-windows
    $ wc -c hello.exe
    4096 hello.exe
    $ file hello.exe
    hello.exe: PE32+ executable (console) x86-64, for MS Windows


    Déclarations de premier niveau indépendantes de l'ordre
    Les déclarations de haut niveau telles que les variables globales sont indépendantes de l'ordre et analysées nonchalamment. Les valeurs d'initialisation des variables globales sont évaluées au moment de la compilation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var y: i32 = add(10, x);
    const x: i32 = add(12, 34);
    
    test "global variables" {
        assert(x == 46);
        assert(y == 56);
    }
    
    fn add(a: i32, b: i32) i32 {
        return a + b;
    }
    
    const std = @import("std");
    const assert = std.debug.assert;

    $ zig test global_variables.zig
    1/1 test.global variables... OK
    All 1 tests passed.


    Le compilateur est écrit en Zig et C++, utilisant LLVM 11 comme back-end, prenant en charge plusieurs de ses cibles natives. Le compilateur est un logiciel libre et open source, distribué sous la licence MIT. Le compilateur Zig fournit la possibilité de compiler du C et du C++, similaire à Clang en utilisant respectivement la commande zig cc et zig c++. Le langage de programmation Nim prend en charge l'utilisation de zig cc comme compilateur C.

    WebAssembly

    « Avec la version 0.9.0, nous avons franchi quelques étapes importantes. Le linker autonome pour wasm a été réécrit, avec les connaissances acquises lors de la construction d'un linker autonome pour wasm », indique la Zig Software Fondation. En effet, le linker est maintenant capable de construire une disposition de la mémoire avec une pile virtuelle, ainsi que d'effectuer des relocations. Ce sont là quelques-unes des fonctionnalités nécessaires à l'implémentation de zig test.

    À ce jour, le backend wasm auto-hébergé est maintenant capable de passer 13 % de tous les tests comportementaux. Avec tous ces changements, la contribution au backend wasm est beaucoup plus facile. L'éditeur de liens est maintenant suffisamment performant pour que seule une connaissance de wasm soit nécessaire pour contribuer au backend.

    RISC-V

    Correction des caractéristiques CPU de l'assemblage RISC-V. Auparavant, Zig ne communiquait pas correctement les caractéristiques du CPU pour RISC-V à l'assembleur Clang, car Clang a une manière différente de transmettre les caractéristiques du CPU pour le code C et pour le code assembleur. Ce commit fait passer à Zig un tag RISC-V -march afin de communiquer les caractéristiques du CPU à Clang lors de la compilation des fichiers d'assemblage.

    Source : ZigLang

    Que pensez-vous du langage Zig ?

    Selon vous, quelle plus value ce langage pourra apporter ?

    Voir aussi :

    Wren, un petit langage de script concurrent rapide basé sur des classes est en cours de conception, il souhaite faire de l'ombre aux autres langages de script par sa concision et ses performances

    D2 : un nouveau langage déclaratif pour convertir du texte en diagrammes, il prend en charge les extraits de code et la syntaxe Markdown

    OK ?, le langage de programmation moderne, dynamiquement typé, élimine la complexité inutile des langages de programmation actuels
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  2. #2
    Invité
    Invité(e)
    Par défaut
    Le C est la pierre de rosette des langages de programmation puisqu'ils sont nombreux à prendre en charge ses types de base, facilitant l'interopérabilité. Autant dire qu'il va être difficile à remplacer.

    Le compilateur Zig prend en charge Webassembly, c'est une bonne chose. Par contre, je pense que Rust est mieux placé sur ce segment vu qu'il semble susciter plus d'enthousiasme chez les programmeurs.

  3. #3
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Hello,

    Je ne vois pas l'intérêt... Quelles sont les améliorations par rapport au C ?

    J'ai un peu regardé le code proposé ici, et je ne vois pas d'améliorations notables. Le fait qu'il n'y ait pas d'allocation dynamiques ne me semble pas être un gain, et je ne vois pas en quoi les tableaux en Zig seraient meilleurs qu'en C.

    Faire un nouveau langage parce qu'il y a un besoin, je peux comprendre.
    Faire un nouveau langage pour la beauté du geste, je peux comprendre.
    Mais là...
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur C++
    Inscrit en
    Octobre 2008
    Messages
    242
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur C++

    Informations forums :
    Inscription : Octobre 2008
    Messages : 242
    Points : 706
    Points
    706
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Hello,

    Je ne vois pas l'intérêt... Quelles sont les améliorations par rapport au C ?
    Je suis un féru du C (et je code tout en C) donc je sais plutôt bien de quoi je parle pour répondre.

    Le C n'est malheureusement pas parfait. Comme on dit souvent pour rigoler “undefined behavior is the name of the game”, alors oui ça permet aux implémentations de faire les choix qui leur sont propres afin d'avoir les meilleures perfs possible mais surtout la plus grande flexibilité. Si je décide de fabriquer mon propre processeur, mon propre OS alors j'ai le droit dans mon cas de dire que faire un overflow de deux entiers signés sera autorisé; or dans la norme c'est bien UB.

    Il y a des problèmes existentiels partout dans le C et même les développeurs les plus avertis se font toujours avoir un jour ou l'autre.

    Si je devais développer mon propre langage, il serait aussi proche du C mais il corrigerait tellement de problèmes qui à mon sens causent aussi parfois sa perte*:

    • Moins d'undefined behavior
    • Meilleur système que les entêtes
    • Build system intégré (combien de fois les packagers de distributions ragent quand un programme utilise un build system maison autre que CMake, meson et autres)
    • RAII ou à minima un système de defer, une fonction qui doit allouer et désallouer en fonction des échecs de fonctions est fastidieuse à écrire (combien ont déjà oublié un pthread_mutex_unlock avec de multiples return ?)
    • Gestion des chaines de caractères fastidieuse
    • Le mot clé const… n'en parlons pas


    Zig corrige déjà pas mal de ces points justement.

  5. #5
    Membre expérimenté

    Homme Profil pro
    Retraite
    Inscrit en
    Octobre 2005
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Aude (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraite
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 479
    Points : 1 347
    Points
    1 347
    Billets dans le blog
    1
    Par défaut
    Le mieux est de rentrer dans le sujet, j'ai du temps étant à la retraite.

    Mais dès le premier abord, on sent que le c/C++ et Rust ont marqué l'orientation.

    Je reviendrai plus tard après un vrai projet. (outils, ide, documentation, forum...)

    Par contre, après avoir fouillé, ce langage est riche et très puissant.

  6. #6
    Chroniqueur Actualités
    Avatar de Bruno
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    Mai 2019
    Messages
    1 852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Rédacteur technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Mai 2019
    Messages : 1 852
    Points : 36 402
    Points
    36 402
    Par défaut Zig, le langage de programmation compilé, inspiré de Rust, serait plus sûr et plus rapide que Rust
    Zig, le langage de programmation compilé, inspiré de Rust et conçu pour concurrencer le C, serait plus sûr et plus rapide que Rust,
    un avis de Zack Radisic, de l’université de Toronto

    Le développeur connu sur le nom Zack Radisic a voulu tester si le langage de programmation Zig est une meilleure alternative à Rust. Il montre quel point l'écriture non sécurisée de Rust serait difficile en construisant un projet qui nécessiterait une quantité substantielle de code non sécurisé. Ensuite, il a réécrit le projet en Zig pour voir si c'était plus facile ou meilleur. Après avoir terminé les deux versions, il a trouvé que « l'implémentation en Zig était plus sûre, plus rapide et plus facile à écrire. »

    Notons que Rust est un langage de programmation compilé multiparadigme, conçu par Graydon Hore alors employé chez Mozilla Research. Utilisé par plusieurs grandes entreprises et par de nombreux développeurs dans le monde, Rust est devenu le langage de base pour certaines des fonctionnalités indispensables du navigateur Firefox et de son moteur Gecko, ainsi que pour le moteur Servo de Mozilla.

    Nom : ZigB.jpg
Affichages : 20717
Taille : 7,7 Ko

    Avec Rust, il est possible de développer des pilotes de périphériques, des systèmes embarqués, des systèmes d'exploitation, des jeux, des applications web, et bien d'autres choses encore. Des centaines d'entreprises dans le monde entier utilisent Rust en production pour des solutions multiplateformes et économes en ressources. Des logiciels connus et appréciés, comme Firefox, Dropbox, et Cloudflare, utilisent ce langage. De la startup à la multinationale, du système embarqué au service web à haute disponibilité, Rust serait une excellente solution.

    Zig est un langage de programmation open source conçu par Andrew Kelley pour garantir les performances telles que la robustesse et la maintenabilité. Andrew a annoncé dans une courte introduction au langage Zig qu’il l’a créé dans le but de concurrencer, voire remplacer à l’avenir, le redoutable langage C dans le cadre de la programmation système. Ainsi, il dit avoir bâti Zig sur quatre principaux aspects afin qu’il soit un langage de programmation pragmatique, optimal, un coffre-fort en matière de sécurité et un langage le plus lisible possible.

    « Je ne suis pas si ambitieux et mon objectif est de créer un nouveau langage de programmation qui sera plus pragmatique que le C. C'est comme essayer d'être plus diabolique que le diable lui-même », a écrit Andrew en introduction à la présentation du langage Zig. Lorsqu’il parle de langage plus pragmatique, il fait allusion au fait « que tout ce qui compte à la fin, c’est de savoir si le langage vous a aidé à faire ce que vous tentiez de faire et d’une manière plus simple que les autres langages ».

    Zig, une meilleure alternative à Rust ?

    Le récupérateur de mémoire est la partie importante, il est difficile de le faire fonctionner et d'être rapide et sûr parce que c'est fondamentalement un problème qui ne joue pas bien avec le vérificateur d'emprunts. Il existe deux façons de le faire de façon sûre en Rust : en utilisant le référence-counting et en utilisant arenas+handles, mais les deux semblent être plus lents que l'approche traditionnelle mark/sweep.

    L'implémentation spécifique de l'interpréteur de bytecode est tirée du livre : Crafting Interpreters : Crafting Interpreters. En particulier, il s'agit d'une VM basée sur la pile pour un langage qui supporte les fonctions, les fermetures, les classes/instances, etc.

    L'implémentation non sécurisée de Rust

    De l'avis de Zack Radisic, l'implémentation non sécurisée de Rust est difficile. Beaucoup plus difficile que le C, il a beaucoup de règles nuancées sur le comportement non défini - grâce au vérificateur d'emprunts - qui rendent facile d'introduire des bogues. En effet, le compilateur effectue des optimisations en supposant que ses règles de propriété soient suivies. « Mais si vous les enfreignez, cela est considéré comme un comportement non défini, et le compilateur continue, appliquant ces mêmes optimisations et transformant potentiellement le code en quelque chose de dangereux. »

    Pour rendre les choses encore plus compliquées, « Rust ne sait pas exactement quel comportement est considéré comme non défini », soutient Zack Radisic. Vous pouvez donc écrire du code qui présente un comportement non défini sans même le savoir.

    Une façon d'y remédier est d'utiliser Miri, un interprète pour la représentation intermédiaire de Rust qui peut détecter les comportements non définis. Plus précisément, Miri est un interpréteur expérimental pour la représentation intermédiaire de niveau moyen (MIR) de Rust. Il peut exécuter les binaires et les suites de tests des projets cargo et détecter certaines classes de comportements non définis. « La source la plus difficile de comportement non défini que j'ai rencontré était liée aux règles d'aliasing de Rust », déclare Zack Radisic.

    Comme mentionné précédemment, Rust utilise ses règles d'emprunt et de propriété pour optimiser le compilateur. Si vous enfreignez ces règles, vous obtenez un comportement non défini. L'astuce consiste à utiliser des pointeurs. Ils n'ont pas les mêmes contraintes d'emprunt que les références Rust classiques, ce qui permet de contourner le vérificateur d'emprunt.

    Par exemple, vous pouvez avoir autant de pointeurs bruts mutables (*mut T) ou immuables (*const T) que vous le souhaitez.
    Si vous transformez un pointeur brut en référence (μt T ou &T), vous devez vous assurer qu'il respecte les règles de ce type de référence pendant toute sa durée de vie. Par exemple, une référence mutable ne peut pas exister tant que d'autres références mutables/immuables existent également.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fn do_something(value: *mut Foo) {
        // Turn the raw pointer into a mutable reference
        let value_mut_ref: &mut Foo = value.as_mut().unwrap();
    
        // If I create another ref (mutable or immutable) while the above ref
        // is alive, that's undefined behaviour!!
    
        // Undefined behaviour!
        let value_ref: &Foo = value.as_ref().unwrap();
    }

    Il serait très facile d'enfreindre cette règle. Vous pouvez faire une référence mutable à certaines données, appeler quelques fonctions, et ensuite, 10 couches plus loin dans la pile d'appels, une fonction peut faire une référence immuable à ces mêmes données, et provoque un comportement indéfini. Le problème est que les pointeurs bruts n'ont pas la même ergonomie que les références. Tout d'abord, vous ne pouvez pas avoir de fonctions associées qui prennent le self comme pointeur brut :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    struct Class {
        /* fields... */
    }
    
    impl Class {
        // Regular associated function
        fn clear_methods(&mut self) {
            /* ... */
        }
    
        fn clear_methods_raw(class: *mut Class) {
            /* ... */
        }
    }
    
    unsafe fn test(class: *mut Class) {
        let class_mut_ref: &mut Class = class.as_mut().unwrap();
        // This syntax is nice and ergonomic
        class_mut_ref.clear_methods();
    
        // But with raw pointers you'll have to just call the function like in C
        Class::clear_methods_raw(class);
    }

    Ensuite, il n'y a pas de syntaxe de déréférencement de pointeur comme ptr->field en C.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // The way to make these readable is to create a variable for each dereference,
    // but that's annoying so in some places I got lazy.
    
    // ew
    (*(*closure.as_ptr()).upvalues.as_ptr().offset(i as isize)) = upvalue;
    
    // ewwwwww
    let name = (*(*(*ptr.cast::<ObjBoundMethod>().as_ptr()).method.as_ptr())
        .function
        .as_ptr()).name;

    Travailler avec des tableaux

    « Si j'ai un pointeur brut sur un tableau de données (*mut T), je peux le transformer en une tranche &mut [T], et je peux utiliser une boucle for ... in ou n'importe quel itérateur pratique (.for_each(), .map(), etc.) », déclare Zack Radisic. Mais le transformer en &mut [T] revient à faire référence à toutes les données du tableau, ce qui permet de violer encore une fois les règles de Rust.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    unsafe fn do_stuff_with_array(values: *mut Value, len: usize) {
        let values: &mut [Value] = std::slice::from_raw_parts_mut(values, k);
        // I can use the ergonomics of iterators!
        for val in values {
            /* ... */
        }
        // I just have to make sure none of the Values are turned
        // into references (mutable or immutable) while the above slice is active...
    }

    Selon Zack Radisic, la solution est d'éviter de faire des références, donc à certains endroits il a fini par écrire des for-loops de style C sur le tableau raw ptr. « Mais les pointeurs bruts sont nuls par rapport aux structures de Rust parce qu'on ne peut pas les indexer et qu'il n'y a pas de vérification hors limites.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    pub struct Closure {
        upvalues: *mut Upvalue
    }
    
    unsafe fn cant_index_raw_pointer(closure: *mut Closure) {
        // Can't do this:
        let second_value = (*closure.upvalues)[1];
    
        // Have to do this, and no out-of-bounds checking
        let value = *(*closure).upvalues.offset(1);
    }

    Miri utilise le modèle Stacked Borrows et peut donc détecter les UB liés aux règles d'aliasing mentionnées ci-dessus, mais les corriger était un défi. « C'est un peu comme lorsque j'apprenais Rust, il y a ces règles qui existent mais je n'en ai pas un modèle mental solide. Je devais comprendre pourquoi ce que je faisais n'était pas correct, puis expérimenter pour trouver un moyen de le corriger », écrit Zack Radisic.

    Notons également que la boucle de rétroaction est beaucoup plus lente parce qu'il n'y a pas de LSP dans son éditeur de code pour le guider, il doit recompiler le programme à chaque fois et voir la sortie de Miri. « Cela a vraiment gâché l'expérience pour moi, précise-t-il. À la fin, je n'écrivais plus vraiment en Rust, mais plutôt dans un langage mi-Rust mi-C qui était beaucoup plus délicat et sujet aux erreurs. »

    « Après avoir passé beaucoup de temps à pratiquer les arts sombres en Rust, j'étais excité à l'idée de quitter Rust, d'apprendre Zig et de commencer à réécrire le projet dans ce langage », confie-t-il.

    L'implémentation

    Selon Zack Radisic, Zig est un langage qui comprend que vous allez faire des choses qui ne sont pas sûres pour la mémoire, il est donc conçu et optimisé pour rendre cette expérience bien meilleure et moins sujette à l'erreur. Voici quelques éléments clés présentés par Zack Radisic :

    Stratégies d'allocation explicites

    Dans Zig, toute fonction qui alloue de la mémoire doit se voir passer un Allocateur. « C'était génial parce que j'ai fait du garbage collector un Allocator personnalisé », indique Zack Radisic. Chaque allocation/désallocation suivait le nombre d'octets alloués et déclenchait le ramasse-miettes si nécessaire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    const GC = struct {
        // the allocator we wrap over that does
        // the heavy lifting
        inner_allocator: Allocator
    
        bytes_allocated: usize
    
        // and other fields...
    
        // `alloc`, `resize`, and `free` are required functions
        // to implement an Allocator
        fn alloc(self: *GC, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) ![]u8 {
            // let the inner allocator do the work
            const bytes = try self.inner_allocator.rawAlloc(len, ptr_align, len_align, ret_addr);
    
            // keep track of how much we allocated
            self.bytes_allocated += bytes.len;
    
            // collect if we exceed the heap growth factor
            try self.collect_if_needed();
    
            return bytes;
        }
    };

    « Ce que j'aime dans ce choix de conception de Zig, c'est qu'il rend sans idiomatique l'utilisation de différentes stratégies d'allocation qui sont optimales pour votre cas d'utilisation », écrit Zack Radisic. « Par exemple, si vous savez que certaines allocations ont une durée de vie similaire et finie, vous pouvez utiliser une autre technique d’allocation pour accélérer votre programme. Cette fonctionnalité existe en Rust, mais elle n'est pas aussi intéressante qu'en Zig. », ajoute-t-il.

    Un allocateur spécial qui détecte les bugs de mémoire

    Lorsqu'il est utilisé, il détecte les use-after-frees et les double-frees. Il affiche une belle trace de pile de quand/où les données ont été allouées, libérées et utilisées.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // All you have to do is this
    const alloc = std.heap.GeneralPurposeAllocator(.{
        .retain_metadata = true,
    }){};

    Pointeurs non nuls par défaut

    La plupart des bugs de sécurité mémoire sont des déréférences de pointeurs nuls et des indexations de tableaux hors limites. Les types de pointeurs bruts de Rust sont nullables par défaut et n'ont pas de vérification de déréférencement de pointeur nul. Il existe un type de pointeur NonNull<T> qui offre plus de sécurité. Les pointeurs Zig, par défaut, sont non nuls et la vérification du déréférencement des pointeurs nuls est également activée par défaut.

    Pointeurs et segments

    Selon zackoverflow, Zig comprend que vous allez travailler avec des pointeurs, et il rend cette expérience agréable. « Un gros problème avec la version non sécurisée de Rust était que les pointeurs bruts avaient une ergonomie terrible. La syntaxe de déréférencement était horrible, et je ne pouvais pas indexer les tableaux de ptr bruts en utilisant la syntaxe slice[idx]. » Les pointeurs de Zig ont la même ergonomie que les références Rust, à savoir que l'opérateur point double le déréférencement du pointeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    fn do_stuff(closure: *Closure) {
        // This dereferences `closure` to get the
        // `upvalues field`
        const upvalues = closure.upvalues;
    }

    Zig dispose également de quelques types de pointeurs supplémentaires qui permettent de distinguer les « pointeurs sur une valeur unique » des « pointeurs sur un tableau » :

    c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    onst STACK_TOP = 256;
    const VM = struct {
        // pointer to unknown number of items
        stack_top:[*]Value,
        // like a rust slice:
        // contains a[*]Value + length
        // has bounds checking too
        stack: []Value,
        // alternative to slices when
        // N is a comptime known constant
        stack_alt: *[STACK_TOP]Value
    };

    Ils supportent l'indexation avec la syntaxe array[idx], alors que les pointeurs classiques (*T) ne le supportent pas, ce qui, selon zackoverflow est vraiment génial pour la sécurité. Le plus intéressant est qu'il est très facile de passer d'un type de pointeur à l'autre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    fn conversion_example(chars:[*]u8, len: u8) []Value {
        // Converting to a []T is easy:
        var slice: []const u8 = chars[0..len];
    
        // And back
        var ptr:[*]u8 = @ptrCast([*]u8, &slice[0]);
    }

    Selon Zack Radisic, les pointeurs "traditionnels", comme ceux que l'on trouve en C/C++, sont très sujets aux erreurs. Rust résout ce problème en ajoutant une couche de façade sur les pointeurs : ses types de référence (&T ou &mut T). Mais malheureusement pour Rust, ses pointeurs bruts ont toujours les mêmes problèmes qu'en C/C++.

    Zig résout ce problème en supprimant simplement une grande partie des pointeurs et en ajoutant des garde-fous supplémentaires. Pour Zack Radisic, écrire une quantité substantielle de Rust non sécurisé réduit vraiment la beauté du langage. « J'avais l'impression de marcher sur la pointe des pieds dans ce verre brisé de comportement indéfini, ou d'écrire dans cette abomination bizarre d'un langage muté moitié Rust/moitié C. » il ajoute : « tout l'intérêt de Rust est d'utiliser le vérificateur d'emprunts, mais lorsque vous devez fréquemment faire quelque chose que le vérificateur d'emprunts n'aime pas... devriez-vous vraiment utiliser le langage ? »

    Rust est un langage entièrement développé de façon ouverte. Il offre la possibilité de construire des logiciels fiables et efficaces. Ses domaines de prédilection étant la programmation système, les applications en ligne de commande, les applications Web via WebAssembly, les services réseaux et les systèmes embarqués. Le langage est également apprécié par sa communauté pour les raisons suivantes :

    • performance : Rust est un langage rapide et économique en mémoire, sans environnement d'exécution, ni ramasse-miettes, il peut dynamiser des services à hautes performances, s'exécuter dans des systèmes embarqués, et s'intégrer facilement à d'autres langages ;
    • fiabilité : le système de typage et le modèle d’ownership de Rust garantissent la sécurité mémoire ainsi que la sécurité des threads. Il permet d'éliminer de nombreuses variétés de bugs dès la compilation ;
    • productivité : Rust dispose d'une excellente documentation, d'un compilateur bienveillant, avec des messages d'erreur utiles. Le langage a également un gestionnaire de paquet et de compilation intégré, divers éditeurs intelligents avec autocomplétions et analyse de type. Il dispose également d’un outil de mise en forme automatique.

    Certain aspect de Rust ne semble pas être suffisamment mentionné lorsque les gens comparent Rust et Zig, et devrait certainement être pris en compte si vous allez faire des choses non sûres pour la mémoire pour des raisons de performance. En tant qu’une personne qui aime Rust, je vais certainement explorer l'utilisation de Zig pour des projets.

    Source : Zack Radisic's blog post

    Que pensez-vous du langage Zig ?

    « Zig, le langage de programmation compilé, inspiré de Rust, serait plus sûr et plus rapide que Rust », partagez-vous cet avis ?

    Selon vous, quelle plus value ce langage pourra apporter ?

    L'analyste de Rust Zack Radisic est-elle pertinente ?

    Voir aussi :

    Zig est un langage de programmation polyvalent et serait une chaîne d'outils permettant de maintenir des logiciels robustes, optimaux et réutilisables

    La version 0.9.0 de ZIG, le langage de programmation compilé, inspiré de Rust et conçu pour concurrencer le C, est disponible, avec une amélioration de l'interface mem.Allocator et bien plus
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  7. #7
    Membre régulier
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juillet 2012
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juillet 2012
    Messages : 21
    Points : 96
    Points
    96
    Par défaut Rust nor not Rust
    Selon mon opinion, je pense que si tu commences à abuser des unsafe, alors Rust n'est pas le langage adapté à ton besoin.
    Go ne l'ai pas non plus adapté car pas assez bas niveau pour son besoin d'implémentation d'interpréteur de Bytecode.

    L'article original parle aussi de microbenchmarks qui s'avèrent 1.5x plus rapide sur Zig que sur Rust.

  8. #8
    Membre expérimenté

    Homme Profil pro
    Retraite
    Inscrit en
    Octobre 2005
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Aude (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraite
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 479
    Points : 1 347
    Points
    1 347
    Billets dans le blog
    1
    Par défaut
    bonjour , voilà ça fait bientôt 5 mois que je programme en ZIG.

    a) on ne peut appréhender un langage qu'avec un vrai projet (là, j'en suis à plusieurs milliers de lignes.)

    b) il faut donner du temps au temps pour d'une part connaître sa philosophie surtout que vos doigt la sente

    c) mon ressenti :

    Très vite, j'ai apprécié la compilation référence croisée qui enlève 3/4 des erreurs,
    que le compilateur est sain et vérifie la cohérence… Reste la manipulation des données et la logique, mais cela pas un langage ne pourra en l'état actuel y remédier.

    Aujourd'hui, je peux dire oui, je peux programmer en ZIG, mais je ne suis pas encore un expert malgré que je passe plusieurs heures sur le projet.

    Bon un sucre, rien n'est fait à votre place et ça, c'est génial, cela vous oblige a beaucoup de rigueur.

    Petit plus je suis content que l'on parle de ZIG, car il y a des entreprises qui déjà se sont engouffrés .... bon, on n'est pas loin de la version 1 ce qu'il y a de drôle et rassurant, c'est qu'au fil de l'eau, je remarque qu'à chaque version en fait vos applications reste stables une bonne chose.

    Une chose aussi qui est agréable ce sont les forums et leurs sites dont un qui montre comment bien programmer et ne sont pas avares de communication. (peu être que cela est dû à la grosseur de la communauté).

    @bientôt

  9. #9
    Membre chevronné Avatar de petitours
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Février 2003
    Messages
    1 935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 935
    Points : 2 014
    Points
    2 014
    Par défaut
    va falloir faire un paquet de Zig zag pour trouver son chemin au milieu de tous ces prodigieux remplaçants du C.
    Il y a 10 sortes de personnes dans le monde : ceux qui comprennent le binaire et les autres

  10. #10
    Candidat au Club
    Homme Profil pro
    Doctorant
    Inscrit en
    Mars 2023
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant

    Informations forums :
    Inscription : Mars 2023
    Messages : 1
    Points : 2
    Points
    2
    Par défaut
    D'après l'article originel, Zig est plus adapté pour implémenter un interpréteur avec garbage collector, avec des fonctionnalités "unsafe", et non en général.
    Et le code produit par l'auteur du blog en Zig est plus rapide que celui qu'il a réalisé en Rust. De tel benchmarks sont intéressants pour l'expérience, mais leurs résultats me laissent souvent perplexe : qui dit qu'il n'y a pas une meilleure façon de faire ?

    Surtout : faire du "Rust unsafe" n'est pas le point fort de Rust, si tout le projet est écrit en Rust unsafe alors c'est que Rust n'est pas vraiment adapté.
    Dans ce cas, pourquoi pas Zig, en effet ! Je sens que je vais me laisser tenter.

  11. #11
    Membre expérimenté

    Homme Profil pro
    Retraite
    Inscrit en
    Octobre 2005
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Aude (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraite
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2005
    Messages : 479
    Points : 1 347
    Points
    1 347
    Billets dans le blog
    1
    Par défaut
    Bonjour, comme promis, je reviens avec un ressenti plus aiguisé.

    Les fuites de mémoires... dans zig ce n'est pas la perdition des pointeurs, mais les allocations de mémoire dont il vous incombe de gérer , on entends par cela le gonflement de la mémoire virtuel lorsque vous ne gérez pas les allocation avec deinit() ou clearandfree() ... Là, il y a du travail pour comprendre le mécanisme

    vous avez 2 possibilité : ex


    pub const allocatorPnl = std.heap.page_allocator;





    cette constant sera associé par ex:
    label = std.ArrayList(lbl.LABEL).init(dds.allocatorPnl);


    et devra être libérée


    soit label.deinit(); on atteint vite la limitation d'utilisation .... ( defer servant à dire lorsque vous sortez de la fonction, veuillez exécuter le code... )

    une autre façon de faire :
    //free memory on module output
    pub var arenaScreen = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    pub var allocatorScreen = arenaScreen.allocator();
    pub fn deinitScreen() void {
    arenaScreen.deinit();

    arenaScreen = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    allocatorScreen = arenaScreen.allocator();
    }




    pourquoi d'abords vous pouvez l'utiliser dans plusieurs fonctions et désallouer avec une fonction
    arenaScreen.deinit();


    ou uiliser la fonction
    deinitScreen()


    ce qui vous permet par exemple de libérer la mémoire ayant attrait à tout se comporte votre Panel après traitement et remet à disposition pour un autre traitement de type Panel

    bien-sur le nettoyage des buffers de vos structures vous incombe comme d'habitude.

    en général, on ne travaille pas avec les pointeurs, mais ont peu passé des adresses ex &Panel a une fonction fn coucou(vpnl : * Panel) .... par coucou(&vpnl) &vpnl devient accessible en mise à jour.

    ______________________________________________________________________________________________

    une autre chose qui est intéressante ce sont le management des erreurs et cela vous oblige soit à rendre par un
    catch unreachable;


    qui ce fou des erreurs, enfin, c'est le programmeur qui en a la responsabilité, et cela, peu être très intéressant, car tout n'est pas sujet à une erreur. lire pus bas.

    maintenant il y a d'autre solution par exemple

    // return index-label ---> arraylist panel-label
    pub fn getIndex(vpnl: *pnl.PANEL , name: [] constu8 ) ErrForms ! usize {
    varidx : usize = 0 ;
    for (vpnl.label.items) |l| {
    if (std.mem.eql(u8, l.name, name)) returnidx ;
    idx+=1;
    }
    return ErrForms.lbl_getIndex_Name_Label_Invalide;
    }




    Ici, on déclare que si aucune conditions n'est réalisée, on retourne une erreur.

    vari = mnu.getIndex(vpnl, vpnl.field.items[vpnl.idxfld].name) catch|err| {dsperr.errorForms(err); return;};



    si err est actif alors, on affiche l'erreur etc...

    bref tout vous est donné pour que votre programme ne beug pas d'une part, a la compilation avec la référence croisée et par le test de valeur .

    Maintenant cela n'empêche pas de désallouer une variable et de vouloir s'en servir ( mais PAN ça va chauffer et provoquer une erreur panic ) mais vous allez vite comprendre

    si je vous ai écrite tout ceci, c'est pour vous aider à bien apprendre tout de suite les allocations de mémoires… alors bien-sur, vous pouvez faire des allocator et ne pas vous soucier du reste. Cependant, votre programme va enfler en mémoire virtuel d'une manière exponentiel et non pas de quelques KO. Chose que j'ai faite et passé du temps à comprendre et tester



    @bientôt

    un petit programme pour jouer avec les alloc.
    conststd = @import("std");





    pub constFIELD = struct {


    regex: [] constu8, //contrôle regex

    };

    constallocator = std.heap.page_allocator;
    pubvarfieldX: std.ArrayList(FIELD) = std.ArrayList(FIELD).init(allocator);

    conststdin = std.io.getStdIn().reader();
    pubfnmain() !void {
    varbuf : [3]u8 = undefined;

    vari : usize = 0;
    varbuffer : [4096] u8 = [_]u8{0} **4096;

    varzone = FIELD {
    .
    .regex = undefined ,
    };
    std.debug.print("stop 1/3 contrôl memoire \r\n",.{});
    buf = [_]u8{0} **3;
    _= trystdin.readUntilDelimiterOrEof(buf[0..], '\n');

    varallouer : bool = true; // allocation

    while ( i < 100) : ( i+=1 ) {
    if (!allouer ) {
    // bufprintZ fournit une addresse a result
    var result = std.fmt.bufPrintZ(buffer[0..], "^[0-9]{s}1,{d}{s}$",.{"{",i,"}"}) catchunreachable;

    zone.regex = result[0..]; // tout va avoir le même résultat
    // la solution serait mettre zone.regex en [] u8
    // zone.regex = allocator.alloc(u8, result.len) catch unreachable;
    // std.mem.copy(u8, zone.regex , result[0..]);
    // ou
    // zone.regex = allocator.dupe(u8, result)
    catch unreachable;

    // ce qui reviendrait à faire un allocprint .
    }
    else zone.regex = std.fmt.allocPrint(allocator, "^[0-9]{s}1,{d}{s}$",.{"{",i,"}"}) catchunreachable;

    fieldX.append(zone) catchunreachable;

    }

    i = 0;
    while ( i < 100) : ( i+=1 ) {
    std.debug.print("{s} {d}\r\n",.{fieldX.items[i].regex, fieldX.items[i].regex.len});
    }

    std.debug.print("stop 2/3 contrôl memoire \r\n",.{});
    buf = [_]u8{0} **3;
    _= trystdin.readUntilDelimiterOrEof(buf[0..], '\n');

    if (allouer ) {
    i = 0;
    while ( i < 100) : ( i+=1 ) {
    allocator.free(fieldX.items[i].regex);
    }
    }

    std.debug.print("stop 3/3 fin \r\n",.{});
    buf = [_]u8{0} **3;
    _= trystdin.readUntilDelimiterOrEof(buf[0..], '\n');

    }


Discussions similaires

  1. Réponses: 0
    Dernier message: 14/04/2020, 14h16
  2. Réponses: 4
    Dernier message: 14/05/2018, 21h25
  3. langages de programmation necessaires pour une application web
    Par nesrine 51092 dans le forum Débuter
    Réponses: 3
    Dernier message: 30/05/2014, 21h25
  4. L'utilisation d'un langage de programmation approprié permettrait une réduction considérable des dépenses
    Par Stéphane le calme dans le forum Débats sur le développement - Le Best Of
    Réponses: 52
    Dernier message: 22/10/2013, 14h35
  5. Réponses: 51
    Dernier message: 17/10/2013, 20h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo