Apprendre C3
(alloc.dev)- C3 est basé sur le langage C et fournit des fonctionnalités avancées comme les modules, la surcharge d’opérateurs, les génériques et l’exécution à la compilation
- Tout en conservant une syntaxe C familière, il intègre des constructions qui renforcent la productivité et la robustesse comme la gestion des erreurs,
deferetforeach - L’introduction de contrats déclaratifs ainsi que des types optionnels et d’un modèle de gestion des erreurs améliore la sécurité et la clarté
- L’environnement de développement prend en charge une bibliothèque standard et un système de build intégrés, ainsi que l’allocation mémoire temporaire et d’autres aspects pratiques
- On y retrouve des similitudes avec le langage Zig dans le build, la création de projet et la structure du code, ce qui laisse entrevoir de nouvelles expérimentations de conception de langage
Vue d’ensemble et caractéristiques de C3
Qu’est-ce que C3 ?
- C3 est un langage construit sur le C existant, qui conserve une syntaxe familière tout en apportant des fonctionnalités difficiles à obtenir en C, comme un système de modules, la surcharge d’opérateurs, les génériques, l’exécution à la compilation, la gestion des erreurs,
defer, les value methods, des contracts progressifs, les slices,foreachet le support des types dynamiques - Sa structure modulaire, fondée sur des namespaces, évite les conflits de noms (
abc::Contextillustre un namespace impératif) - Son objectif principal est d’augmenter la productivité tout en fournissant en toute sécurité des fonctionnalités modernes de programmation système
Caractéristiques du langage
Exemple Hello World
- Syntaxiquement proche du C
- Les déclarations de fonction doivent utiliser explicitement le mot-clé
fn - Les fonctions de la bibliothèque standard pour l’entrée/sortie sont puissantes et peuvent afficher directement divers types
Boucle foreach
- Contrairement au C, la syntaxe
foreachest prise en charge nativement - Pour itérer par référence, il faut écrire
&devant le nom de variable (fonction avancée) breaketcontinuesont pris en charge, avec un fonctionnement proche duforeachd’autres langages
Boucle while
- Avant C99, il n’était pas possible d’écrire une déclaration dans la condition d’un
while, alors qu’en C3 c’est autorisé
enum et instruction switch
- L’instruction
switchprend en charge lebreakimplicite (le mélange implicite/explicite pourra diviser selon les goûts) - Le mot-clé
nextcasepermet un passage explicite d’un case à l’autre (pratique pour implémenter une table de sauts) - Il devient possible de contrôler plus simplement des flux
switch-casequi étaient plus complexes dans des langages comme Zig ou C
Mot-clé defer
- À la sortie du scope, les instructions enregistrées avec
defersont exécutées en ordre inverse, ce qui garantit proprement le nettoyage des ressources - Utilisation de
deferen combinaison aveccatchettrypour contrôler les flux de gestion d’erreurs
struct et union
- Les
structpeuvent contenir des sous-struct/unionnommées ou anonymes, ce qui facilite la conception de patterns de tagged union - La distinction entre les formes anonymes (avec duplication de champs de même nom) et les collisions de noms est strictement définie
Gestion des erreurs
- Le symbole
?prend en charge les types optionnels, en unifiant erreurs et valeurs optionnelles pour plus de commodité - Le mot-clé
catchpermet de traiter l’état vide (sans Optional) ou une branche d’erreur - Contrairement à Rust ou Zig, la distinction entre erreur et valeur optionnelle est moins marquée (avantage : simplicité, inconvénient : intention moins explicite)
- L’opérateur
!(rethrow) permet de propager une exception
Contrats (Contracts)
- Les préconditions et postconditions d’une fonction (
Require/Ensure) s’écrivent entre<* .. *>(vérification des conditions à la compilation) - L’analyse de fold à la compilation est aussi prise en charge (l’analyse statique n’est pas encore implémentée)
Méthodes de struct
- Les méthodes associées sont définies via une notation de type + point (
Foo.next), avec namespaces inclus (y compris pour les types primitifs) - Les méthodes sont autorisées sur tous les types, y compris
struct,unionetenum
Macros
- Macros fondées sur l’évaluation à la compilation (mot-clé
macro) - Les paramètres à la compilation sont gérés avec
$, et#permet un passage avant évaluation - Style C (réduction des problèmes de macros imbriquées, accent mis sur la stabilité de l’AST, vérification avec préfixe
@, etc.) - La réflexion de type et l’exécution à la compilation sont gérées par les macros
Propriétés de type
alignof, kindof, extnameof, sizeof, typeid, methodsof, has_tagof, tagof, is_eq, is_ordered, is_substruct- Adapté à la métaprogrammation et à la réflexion
Littéraux Base64/Hex
- Les formes
b64"..."etx"..."permettent de déclarer directement des séquences d’octets - Le macro intégré
$embedpeut les remplacer (dans les faits, leur usage semble peu fréquent)
Types primitifs
- Nombreux types de base :
int,uint,char(toujours unsigned),bool,float,int128/uint128, etc. - Types distincts pour les pointeurs et tailles, comme
iptr,uptr,isz,usz(un peu moins intuitifs) - Contrairement au C, la taille en bits est garantie
Divers
- Large ensemble de fonctionnalités, dont la surcharge d’opérateurs, le sous-typage de structures, les génériques, le runtime dispatch, le type
anyet les bitstructs
Pratique : retour d’expérience avec C3
Installation de C3
- Deux méthodes sont prises en charge : binaire précompilé depuis le site officiel ou compilation directe depuis les sources
- Installation de LLVM et LLD requise (en cas de problème de linkage, utiliser les flags CMake
-DLLVM_DIRet-DLLD_DIR) - Certaines distributions n’incluant pas les bibliothèques LLD, il est recommandé de télécharger directement les binaires
- Le compilateur C3 dépend de
libtinfo
Création de projet
- La commande
c3c initgénère une structure de dossiers standard (LICENSE/README.md/project.json/src, etc.) - Mise en place du projet avec Bluild, cibles de build, configuration des sources, etc. (proche de Zig et Cargo)
- Le fichier
main.c3par défaut est très concis (avis : bien adapté aux nouveaux utilisateurs)
Créer une calculatrice
Conception et objectif
- Implémenter un parseur à descente récursive (Recursive Descent Parser) et la logique centrale d’une calculatrice afin de pratiquer diverses syntaxes de C3 : fonctions, entrées/sorties, gestion mémoire, boucles, etc.
- Objectif : identifier directement les points forts et les aspects moins confortables du langage, notamment en matière d’intuitivité syntaxique et de productivité en situation réelle
Traitement des entrées
@poolpermet d’utiliser un allocateur temporaire (tmem), avec libération automatique de la mémoire à la fin du scope (arena allocator)- Le langage propose
tmem(temporaire) etmem(général) comme modes de gestion mémoire standard, avec un modèle de passage d’allocateur par fonction (mélange des atouts de Zig et du C) - La fonction
maindoit obligatoirement déclarer une valeur de retour (contrainte imposée par le compilateur) - Les fonctions dont la valeur de retour peut être ignorée sont annotées avec l’attribut
@maydiscard(pour éviter un oubli abusif)
Implémentation du tokenizer
- Décomposition de l’entrée utilisateur en liste de tokens
- Utilisation de diverses structures de contrôle de la bibliothèque standard de C3, comme
List, la syntaxeforeachetswitch-case(nextcase, combinaison debreakimplicite/explicite) - Une certaine confusion existe autour de la syntaxe des slices (indices aux deux extrémités inclus) et des slices de longueur 0 (une syntaxe distincte de spécification de longueur existe)
- La combinaison d’allocateurs temporaires et généraux rend la gestion mémoire transparente et flexible, avec un résultat supérieur à certains autres langages comme Rust
Implémentation du parseur
- Retour d’expérience sur l’écriture directe du parseur (omis)
Conclusion et avis d’ensemble
- C3 cherche le point de rencontre entre les langages système traditionnels et une conception moderne
- Conçu en étudiant Zig, Rust et C, il vise à concilier performances et stabilité du code
- Se distinguent notamment la modularité, la gestion sûre de la mémoire/des erreurs/des contrats, la métaprogrammation puissante et un système de build intuitif
- La courbe d’apprentissage reste progressive pour quelqu’un ayant déjà de l’expérience en C
- L’écosystème encore immature (serveur de langage, IDE, etc.) ainsi que certaines préférences de syntaxe restent à améliorer
- Il mérite l’attention comme langage alternatif de nouvelle génération pour le développement bas niveau et système
Aucun commentaire pour le moment.