VT2021 Zig fiche

Analyse du Langage Zig
MALOD Victor (victor.malod@outlook.fr) - PARA Yaël (ya38able@gmail.com)

Résumé
Mots clés : Zig, langage, performances, programmation

Zig est un langage de programmation qui met en avant la robustesse, l'optimalité et la réutilisation du code. Son créateur s'est inspiré de la simplicité du langage C afin de concevoir un langage qui va à l'essentiel et fournit les fonctionnalités indispensables des langages de programmation orienté objet tout en restant lisible et accessible. Ce langage est par ailleurs devenu un concurrent direct du langage C. Dans cette synthèse nous étudions les avantages de ce langage tout en le comparant avec ses concurrents en termes de performance, simplicité et d'accessibilité.

Abstract
Keywords : Zig, language, performance, programming

Zig is a programming language which emphasizes robustness, optimality and code reuse. Its creator was inspired by the simplicity of the C programming language and designed a language that provides the essential features of object-oriented programming languages while remaining simple and easy to learn. This language has also become a direct competitor of the C language. In this study, we will study the advantages of this language while making a comparison between Zig and its competitors in terms of performance, simplicity and accessibility.

Synthèse
A. Objectifs du langage

L'objectif principal du créateur de Zig est de fournir une version améliorée du langage C sans ses défauts.

En effet le créateur du langage s'est inspiré du langage C lors de la conception, car il apprécie la simplicité du langage C, le fait qu'on puisse suivre facilement le flux de contrôle lors de l'exécution d'un programme, et il a souhaité avec ce nouveau langage conserver cet aspect minimaliste tout en proposant des fonctionnalités que l'on peut retrouver dans des langages orienté objet comme C++ (comme par exemple les types génériques).

Ce langage vise à être un remplaçant du langage C, il peut donc être utilisé dans les mêmes types de projets que ceux utilisant le langage C. Il a été utilisé pour des jeux, comme Oxid, mais également pour la programmation d'émulateurs, des serveurs HTTP/DNS, des kernels, des bases de données, et des compilateurs entre autres. Il peut par ailleurs être utilisé sur des microcontrôleurs. Une liste de projets utilisant le langage Zig peut être trouvée sur ce lien.

B. Caractéristiques du langage

Les informations concernant les caractéristiques présentées ici proviennent de la page d'overview du langage. Toutes les caractéristiques intéressantes du langages ne sont pas présentées ici, pour des soucis de concision.

Pas de flux de contrôle caché

Un passage d'un bloc de code à un autre est uniquement causé par des appels de fonctions et il n'y a pas de flux de contrôle caché. Dans d'autres langages, cela peut ne pas être le cas :

- Par exemple en D, il existe ce qu'on appelle des property functions, qui sont des méthodes appelées avec la même syntaxe que l'accès à un champ d'une structure. - De même, en C++ il existe l'overloading d'opérateur, ce qui permet de spécifier le comportement d'un opérateur par une fonction. Dans cette portion de code, l'opérateur pourrait également appeler une fonction. - Enfin en Java, une exception peut être levée, interrompant le flux d'exécution.

De façon générale, le langage est conçu de façon à ce que si dans le code on n'observe pas d'appel de fonction, il n'y aura pas d'entrée dans une fonction. Cela permet d'améliorer la lisibilité du code, et donc sa compréhension.

Pas de préprocesseur

Le préprocesseur C est l'outil qui assure la compilation des programmes informatiques écrits dans les langages de programmation C. Il permet principalement l'inclusion d'un segment de code source disponible dans un autre fichier avec la directive include, ainsi que la compilation conditionnelle avec les directives ifndef (plus d'informations à ce sujet ici) Le principal problème du préprocesseur selon son créateur est que le langage utilisé pour les directives du préprocesseur est indépendant de la syntaxe du langage C, de sorte que le préprocesseur C puisse être utilisé isolément pour traiter d'autres types de fichiers sources (comme ceux du C++) Cela a 2 conséquences majeures : - L'utilisation de la commande ifdef dans des fichiers source en C peut provoquer la compilation de code qui contient des erreurs de syntaxe. En effet, après le traitement du fichier source par le préprocesseur, le compilateur peut ne pas détecter des erreurs de syntaxe dans des lignes de code qui sont exclues par les directives ifdef et endif. - L'utilisation de la directive include permettant l'inclusion de portions de codes provenant d'un autre fichier en C est considéré comme le plus grand contributeur à des temps de compilation lents pour les programmes C. Afin de résoudre ce problème, le langage Zig fournit les fonctionnalités du préprocesseur C dans le langage Zig. Cela résout les pertes de performances (car on gère un seul langage contrairement en C) et permet de rendre les erreurs de syntaxes visibles, car les instructions équivalentes à celles du préprocesseur en langage C subissent les mêmes vérifications à la compilation que celles du code basique. Il n'y a plus de phase de préprocessing (traduction des directives du préprocesseur) lors de la compilation en Zig, ce qui améliore les performances et évite l'exclusion de code par les directives équivalentes à ifdef et endif (plus d'informations sur les pertes de performance avec le préprocesseur C ici).

Interopérable avec C

Un très gros avantage de Zig qu'on ne retrouve pas dans tous les langages c'est qu'il est interopérable avec son grand frère : le C.

L'interopérabilité c'est la capacité de fonctionner ensemble et de partager des données.

Dans notre cas, Zig peut appeler des fonctions C, et inversement C peut appeler des fonctions Zig (il suffit de mettre le mot clé "export" dans notre programme Zig). Ceci n'est pas possible dans tous les langages, même C à de la peine à fonctionner avec C++ (exemple : la surcharge d'opérateur en C++ est difficilement transmissible en C, pareil pour la notion de destructeur d'objet). Cette capacité de Zig à pouvoir s'adapté à un autre langage découle de son compilateur, car il est livré avec gcc, clang et g++ (c'est pour cela qu'on peut écrire des portions de code en C dans un source Zig), on peut donc compiler notre code C avec Zig si on le souhaite. Zig offre même la possibilité de traduire du code c en code Zig dans les outils de son compilateur (biensûr le code ne sera pas parfait mais c'est un point intéressant).

Exécution de code à la compilation avec 

Une très grande force de Zig se traduit par l'utilisation du mot clé, avec lequel on peut demander au compilateur d'exécuter du code durant la compilation du programme. Il existe différents cas d'utilisation, qui inclus la robustesse ou la performance du code. On peut aussi simplement faire des tests directement à la compilation. permet d'indiquer au compilateur que la variable/fonction/bloc de code concerné est à évaluer à la compilation avant de générer un exécutable.

fn multiply(a: i64, b: i64) i64 { return a * b; }

pub fn main void { const len = comptime multiply(4, 5); // example use of comptime const my_static_array: [len]u8 = undefined; }

Dans l'exemple ci-dessus on est dans le cas où l'on souhaite éviter de faire le calcul de  à chaque lancement du programme, on utilise donc   pour faire cette tâche une fois et une bonne fois pour toute à la compilation. Dans la démonstration on utilise  d'une manière autre, qui permet d'assurer que le développeur utilise une fonction de la manière souhaitée (plus de détails dans la démonstration). Il existe des cas plus complexes de l'utilisation de  qui permettent aussi de dérouler une boucle et donc d'enlever la notion de boucle dans le code assembleur généré. On parle encore ici d'optimisation. On peut aussi utiliser comptime dans des cas plus complexes dont je ne parlerai pas ici (avec des types génériques par exemple).

C. Performances du langage

Temps de compilation

Une comparaison du temps de compilation de différents langages peut être retrouvée ici : https://vlang.io/compilation_speed. Ce test a été créé par le créateur du langage V afin de démontrer la supériorité de son langage en ce qui concerne les temps de compilation. On remarque que Zig fait partie des temps de compilation les plus courts, même en comparaison avec d'autres langages bas niveau tels que RUST. Il reste bien en dessous du temps de compilation de C++, cependant il met le double de temps en comparaison avec le langage C.

Temps d'exécution

Une comparaison de différents temps d'exécution entre les langages sur des problèmes donnés peut être trouvée ici.

Concernant les performances d'exécution, les chiffres que nous avons étudiés concernent Zig, C, C++ et Rust sur les problèmes suivants : "Hello World", "nbody", "nsieves". "Hello World" est un programme basic avec un affichage sur la sortie standard, "nbody" est une simulation de progression des astres du système solaire à 5 million d'étapes (caculs "simples" mais en grande quantité). Et nsieves trouvent les 12 premiers nombres premiers en partant de 0. Pour chacun des tests, Zig a de bons résultats, surtout sur le dernier problème, où il passe 2 fois moins de temps que C et C++. Voici un tableau récapitulatif des chiffres étudiés :



Veille Technologique 2021

 * Année : VT2021
 * Sujet : Zig Language
 * Slides : [[Media:VT2021-Zig-Presentation.pdf|Slides]]
 * Auteurs : Yaël Para & Victor Malod