URL: https://linuxfr.org/news/le-langage-d--2 Title: Le langage D Authors: Jonathan MERCIER B16F4RV4RD1N, Bruno Michel, baud123, claudex, patrick_g, Benoît, lordblackfox, Amine "nh2" Brikci-Nigassa et NeoX Date: 2012年06月07日T20:25:11+02:00 License: CC By-SA Tags: fedora Score: 51 Le langage D est un langage extrêmement puissant et intuitif à l'utilisation. Nombre d'entre nous sommes au courant de l'existence de ce langage. Mais il reste pourtant mal connu. Par le biais de cette dépêche je vous propose de découvrir ou redécouvrir ce puissant langage. ![dlogo](http://dlang.org/images/dlogo.png) ---- [Le langage D référence et API](http://dlang.org/) [Environnement de programmation pour le D avec Fedora 17](https://fedoraproject.org/wiki/Features/F17_D2_programming) [wikipedia Langage D](http://fr.wikipedia.org/wiki/D_%28langage%29) [wikipedia Langage D (plus à jour que la version française)](http://en.wikipedia.org/wiki/D_%28programming_language%29) [Grand tutorial sur le langage D](http://ddili.org/ders/d.en/) ---- # Présentation du langage Le D se veut adapté au monde moderne du programmeur. Pour cela il tend à combiner puissance de calcul et productivité, la performance d’exécution des langages compilés avec l'intuition des langages de script. Je préfère vous prévenir une fois l'étape d’apprentissage du langage acquise, il est fortement possible que vous ne souhaitiez plus revenir en arrière. Le D supporte plusieurs paradigmes, l'expérience a souvent montré que de se restreindre à un paradigme complique dans certains cas la réponse au problème donné. * [Orientée objet](http://en.wikipedia.org/wiki/D_%28programming_language%29#Object-oriented) * [Fonctionnelle](http://en.wikipedia.org/wiki/D_%28programming_language%29#Functional) * [Concurentielle](http://en.wikipedia.org/wiki/D_%28programming_language%29#Concurrent) * [Impérative](http://en.wikipedia.org/wiki/D_%28programming_language%29#Imperative) * [Metaprogrammation](http://en.wikipedia.org/wiki/D_%28programming_language%29#Metaprogramming) Ainsi le développeur est mieux armé pour répondre aux différentes problèmatique. Le langage D a pour devise :> « Si un langage peut récupérer 90 % de la puissance du C++ mais seulement 10 % de sa complexité, cela vaut largement le coup. » _— Walter Bright_ # Quelques exemples de code À travers différents exemple de code nous allons vous montrer les bases du langage. L'objectif est d'être bref et de montrer quelques nouveautés facilitant la vie du développeur. ## Bonjour paul Le traditionnel `bonjour`. ```d import std.stdio; void main ( string[] args){ writef("Bonjour: %s", args[1] ); } ``` L'instruction `import` indique ici que l'on souhaite utiliser des fonctionnalités définies dans le module `stdio` d'où provient la fonction `writef`. Le programme commence a exécuter les instructions à partir de la fonction principale `main`. Cette fonction récupère ici les paramètres donnés via la ligne de commande. La fonction `writef` va écrire sur la sortie standard le mot _Bonjour_ suivi du premier mot donné via la ligne de commande. ``` $ ldc2 hello.d $ ./hello paul Bonjour paul ``` # Une petite addition À travers une opération simple qui est l'addition, nous allons découvrir comment écrire et utiliser les fonctions et les fonctions modèles (template). ```d import std.stdio; @safe pure nothrow size_t ajoutez( immutable size_t a, immutable size_t b = 0){ return a + b; } void main ( string[] args ){ size_t c = ajoutez( 2 , 3 ); size_t d = ajoutez( 2 ); size_t e = ajoutez( cast(size_t)2.3 , cast(size_t)3.3 ); writef( " 2 + 3 = %d | 2 + 0 = %d | 2.3 + 3.3 = %d", c, d, e); } ``` ``` $ ldc2 addition.d $ ./addition 2 + 3 = 5 | 2 + 0 = 2 | 2.3 + 3.3 = 5 ``` La fonction `ajoutez` prend deux paramètres de type _entier positif_ et retourne une valeur de type _entier positif_. La fonction `ajoutez` tronque les valeurs décimales dues aux types utilisés. Si le second paramètre est omis il prendra par défaut la valeur 0. **En Bref :** * `@safe` indique que la fonction est sûre, devant suivre les règles décrites [ici](http://dlang.org/function.html#Safe), il s'agit d'éviter des [comportements indéfinis](http://dlang.org/glossary.html#undefined_behavior) pouvant poser des problèmes de sécurité comme les *cast* de variable vers un pointeur, l'écriture de langage d'assemblage *inline*, le *catch* d'exception ne dérivant pas de la classe *Exception* ... * `pure` indique que : * les mêmes paramètres donneront toujours le même résultat (si a vaut et b vaut 2, a+b sera toujours égale à 4) 2+2 est donc calculé une fois ; les autres fois il connaîtra le résultat sans calculer. * Pas d'effet de bord en n'effectuant pas de modification d'état des variables comme `a+=2` * `nothrow` indique que la fonction ne lève pas d'exception * `immutable` les variables ne peuvent pas changer d'état. ```d import std.stdio; T ajoutez(T,U)( T a, U b ){ return a + b; } void main ( ){ double c = ajoutez( 2.4 , 3 ); auto d = ajoutez( 2 , 3 ); writefln( "2.4 + 3 = %f", c); writefln( "2 + 3 = %d", d); } ``` ``` $ ldc2 addition2.d ./addition2 2.4 + 3 = 5.4 2 + 3 = 5 ``` Afin de pouvoir adapter dynamiquement la fonction `ajoutez` aux types donnés en paramètre et ainsi éviter d'écrire plusieurs fonctions combinant toutes les possibilités, on utilise les fonctions template. Le D est capable de déterminer automatiquement le type des variables retournées, on peut ainsi utiliser le mot clé `auto` en lieu et place du type. # Les conditions par l'exemple ```d string a = "bonjour"; if( a == "coucou") writeln( "ok" ); else if( a == "bonjour") writefln( "%s", a ); else writeln("raté"); ``` Si la variable `a` est égale à `coucou` on écrit sur la sortie standard `ok`. Sinon si `a` est égale à `bonjour` on écrit sur la sortie standard `bonjour`. Sinon pour tous les autres cas on écrit sur la sortie standard `raté`. **Note :** Les blocs ne contenant qu'une seule instruction sont dispensés des accolades `{}` . Ceci est vrai pour les conditions et les boucles. ```d string a = "bonjour"; switch(a){ case "coucou": writeln( "ok" ); break; case "bonjour": writefln( "%s", a ); break; default: writeln("raté"); } ``` Ce bout de code fait exactement pareil que la suite `if`, `else if`, `else` précédente. # Les tableaux ## Les tableaux Dynamiques ```d size_t[] tab = new size_t[](5); // tableau dynamique de taille 5 size_t[] tableau = [ 0, 1, 2]; // tableau dynamique d'entier positif tableau.length; // retourne la taille de 3 tableau[0]; // Accède au premier élément du tableau tableau[3]; // erreur le tableau contient 3 éléments en partant de 0 tableau.length = tableau.length + 1; // augmente la taille du tableau tableau[3] = 3; // Assigne la valeur de 3 en 4ème position ``` ## Les tableaux statiques ```d size_t[3] tableau = [ 0, 1, 2]; // Tableau statique d'entier positif tableau.length; // Retourne la taille de 3 tableau[0]; // Accède au premier élément du tableau tableau[3]; // Erreur le tableau contient 3 éléments en partant de 0 tableau.length = tableau.length + 1; // Erreur on peu pas augmenter // la taille d'un tableau statique ``` ## Les tableaux associatifs ```d size_t[string] catalogue; // la clé est une chaine de caractère, // la valeur un entier positif catalogue["fedora"] = 17; // ajoute la clé fedora asssocié à la valeur 17 "fedora" in catalogue; // retourne vrai (true) catalogue["fedora"]; // retourne la valeur 17 ``` ## Les tableaux de types différents ```d import std.stdio; import std.variant; void main( string[] args ){ Variant[] v = new Variant[](3); v[0] = 1; v[1] = 1.2; v[2] = "test"; writeln( v ); } ``` ``` $ ldc2 test_variant.d $ ./test_variant [1, 1.2, test] ``` ## Les tableaux de caractères * le guillemet simple `'` désigne un caractère `char lettreA = 'a';` * le guillemet double `"` désigne une chaine de caractère `string mot = "salut";` * le backticks (accent grave)`` ` `` désigne une chaine de caractère gardant le formatage (wysiwyg) ``string mots = `J'aime le D. C'est super cool comme langage`.`` # Répéter le code : Les boucles ## La boucle _Pour chaque_ (foreach) ```d import std.stdio; void main ( ){ foreach( size_t count; 0 .. 3) write( count, " " ); // écrit sur la même ligne writeln(); // saut de ligne size_t result = 0; foreach( size_t count; 0 .. 3){ result += 2; write( result, " " ); // écrit sur la même ligne } writeln(); // saut de ligne foreach( size_t count, string prénom; [ "jean", "Marie", "Paul" ] ) writef( "%d ↪ %s | ", count, prénom ); // écrit sur la même ligne writeln(); // saut de ligne string[string] personnes = [ "jean": "Debian", "Marie": "CentOs", "Paul": "Fedora" ]; // tableau associatif foreach( string prénom, string disribution; personnes ) writefln( "%s utilise GNU Linux %s", prénom, disribution ); foreach( ref string distribution; personnes ) distribution = "Fedora"; writeln( personnes ); } ``` ``` $ ldc2 test_foreach.d $ ./test_foreach 0 1 2 2 4 6 0 ↪ jean | 1 ↪ Marie | 2 ↪ Paul | jean utilise GNU Linux Debian Paul utilise GNU Linux Fedora Marie utilise GNU Linux CentOs ["jean":"Fedora", "Paul":"Fedora", "Marie":"Fedora"] ``` La boucle `foreach` s'utilise de façon intuitive et peut avoir au besoin un compteur comptant le nombre d'itération. Afin de modifier sur place le contenu du tableau il suffit de préciser que la valeur est une référence (`ref`) à l'élément du tableau. Vous remarquerez qu'il est possible d'utiliser des caractères unicode pour le nom des variables. En effet, le D gère nativement l'unicode, par exemple les statisticiens peuvent utiliser les lettres lambda `λ`, mu `μ`, rho `ρ` et sigma `σ`. ##La boucle _Pour_ (for) ```d import std.stdio; void main ( ){ size_t result = 0; for( size_t count = 0 ; count <= 10; count++ ){ result += 2; writeln( result ); } } ``` ## La boucle tant que (while) ```d bool isRunning = true; size_t i = 0; while( isRunning ){ if( i>= 10 ) isRunning = false; else i++; } ``` # Les structures de données Il y a deux structures de données possibles : les structures et les classes. Les classes sont utilisées lorsque l'on a recourt à l'héritage ; dans tous les autres cas on utilise les structures. **Note :** * Surcharge : * Les méthodes peuvent avoir le même nom mais prenant des paramètres différents * Une méthode peut avoir le même nom et prenant les mêmes paramètres que ceux d'une classe parente. On parle de même signature : _nom de la fonction + paramètres_. ## Les structures Les structures en D ont eu quelques améliorations permettant une utilisation simple et efficace. ```d import std.string : format, toUpper; // import sélectif import std.stdio; struct Personne{ private: string _nom; string _prénom; size_t _âge; public: this(string nom, string prénom, size_t âge = 18){ // constructeur _nom = nom; _prénom = prénom; _âge = âge; } string toString(){ return "Je m'appelle %s %s et j'ai %d ans".format( _nom.toUpper(), _prénom, _âge); } @property string nom(){ return _nom; } @property string prénom(){ return _prénom; } @property size_t âge(){ return _âge; } } void main(){ Personne p1 = Personne( "dupont", "paul", 34 ); Personne p2 = Personne( "durant", "louis" ); writeln( p1 ); writeln( p2 ); if( p1.nom == "dupont" ) writeln( "Bonjour dupont" ); else writefln( "non!, Je m'appel %s", p1.nom ); } ``` ```d $ ldc2 personne.d $ ./personne.d Je m'appelle DUPONT paul et j'ai 34 ans Je m'appelle DURANT louis et j'ai 18 ans Bonjour dupont ``` **En bref :** * import sélectif * les structures peuvent avoir un constructeur (pas obligatoire) * les variables peuvent être publiques ou privées (`protected`, aucun intérêt en absence d'héritage) * `@property` permet de ne pas utiliser `()` lors d'appel de méthode * `toString` permet de représenter l'instance par une chaîne de caractère ## Les classes Les classes s'utilisent comme les structures et permettent l'implémentation de l'héritage d'une autre classe ou d'une interface. Le langage D ne supporte pas l'héritage multiple. En reprennant l'example de la structure précédente : ```d import std.string : format, toUpper; // import sélectif import std.stdio; class Personne{ protected: string _nom; string _prénom; size_t _âge; public: this(string nom, string prénom, size_t âge = 18){ // constructeur _nom = nom; _prénom = prénom; _âge = âge; } override string toString(){ return "Je m'appelle %s %s et j'ai %d ans".format( _nom.toUpper(), _prénom, _âge); } @property string nom(){ return _nom; } @property string prénom(){ return _prénom; } @property size_t âge(){ return _âge; } } class Mage : Personne{ protected: size_t _level; size_t _mana; public: this(string nom, string prénom, size_t âge = 18, size_t level = 1){ super( nom, prénom, âge); _level = level; _mana = _level * 10; } @property size_t bouleDeFeu(){ // puissance de la boule de feu size_t dégât = 0; if( _mana> 5 ){ _mana -= 5; dégât = _level * 2; } return dégât; } @property size_t level(){ return _level; } @property size_t mana(){ return _mana; } override string toString(){ return "Je suis %s %s le mage de feu".format( _nom.toUpper(), _prénom); } } void main(){ Personne p1 = new Personne( "dupont", "paul", 34 ); Mage m1 = new Mage( "durant", "louis", 18, 15 ); writeln( p1 ); writeln( m1 ); if( cast(Mage) m1 ) writefln( "Bonjour je suis un mage de niveau %d", m1.level); } ``` ``` $ ldc2 mage.d $ ./mage Je m'appelle DUPONT paul et j'ai 34 ans Je suis DURANT louis le mage de feu Bonjour je suis un mage de niveau 15 ``` **En bref :** * On utilise les classes si on utilise l'héritage * Création d'une instance avec le mot clé `new` (ce n'est pas vrai pour les structures) * Spécification de surcharge de méthode avec `override` # Pour aller plus loin ## Un aperçu sur la parallèlisation Un petit exemple d'itération parallèle, plus d'exemple sur le [site officiel](http://dlang.org/phobos/std_parallelism.html). ```d import std.stdio; import std.parallelism; void main(){ TaskPool taskPool = new TaskPool(9); string[] prénoms = [ "Paul", "Jean", "Pierre", "Julie", "Robert", "Jonathan", "Julien", "Sabrina", "Laetitia" ]; foreach( prénom; taskPool.parallel(prénoms) ) writeln(prénom); taskPool.finish(); } ``` ``` $ ldc2 test_parallel.d $ ./test_parallel Paul Jean Pierre Julie Julien Jonathan Robert Sabrina Laetitia ``` # Une delegate pour la route (closure) ## À la mode fonctionnelle ```d import std.stdio; void main(){ immutable size_t n = 2; immutable size_t x = 1; pure size_t inc( size_t k ){ return n + k; } pure size_t f( in size_t delegate(size_t) pure dg1, in size_t delegate(size_t) pure dg2) { return dg1( x ) + dg2( x ); } immutable size_t delegate(size_t k) pure dg = &inc; writeln( f( dg , dg ) ); } ``` ``` $ ldc2 fonctionnelle.d $ ./fonctionnelle 6 ``` **En bref :** * La fonction `inc` (pour incrémente) * capture la variable `n` qui est dans le contexte local * retourne la somme de `n` local + `k` passé en paramètre * la fonction `f` * prend en paramètre deux fonctions ayant la même signature que `dg` * additionne le résultats des deux fonctions ( 2 + 1 ) + ( 2 + 1 ) * retourne le résultat * La fonction `dg` positionne la fonction `inc` comme delegate * prenant en paramètre un entier positif * retournant comme résultat un entier positif ## De façon non-fonctionnelle ```d import std.stdio; void main(){ size_t n = 2; size_t x = 1; void f( size_t a){ writeln( a ); } int inc(size_t k) { n = n + k; return n; } //incremente n d'un pas k f( inc(x) + inc(x) ); // f( 2+1 + 3+1 ) => 7 } ``` **En bref :** * À la différence de la façon fonctionnelle * n subit un changement d'état dans la fonction `inc` * la fonction `inc` * capture la première fois `n` valant `2` * capture la seconde fois `n` valant `3` * car `n` a subi un changement d'état au premier passage dans `inc` # Distributions linux conseillées pour le D * Fedora fournit dans les dépôts officiels : * ldc _(compilateur libre basé sur LLVM)_ * phobos 2.059 _(bibliothèque standard)_ * tango2 * gtkD _(un wrapper pour gtk )_ * derelict2 _(pour les appli 3D avec des wrapper comme pour SDL... )_ * dustmite _(outil pour réduire un programme en un code minimal produisant le segfault)_ * Debian via le dépôt non-officiel [d-apt](http://code.google.com/p/d-apt/wiki/APT_Repository) * dmd _( compilateur avec restriction de droit )_ * gtkd * tango * plot2kill * dcollections * orange _( serialisation )_ * scid * spiritd * dstats * msgpack * derelict * gl3n * dsqlite * vibe - Archlinux fournit dans son dépôt officiel : - ldc - phobos - et d'autres paquets (derelict, gtkd...) dans AUR, du côté des contributions utilisateurs. # Mythes et légendes De nombreuses idées persistent, nous allons ici en répertorier quelques unes. Dans la catégorie, `le langage D est`: * Un langage propriétaire : **Faux** : les compilateurs _ldc_ et _gdc_ fournissent une implémentation _libre_ de ce langage * Peu utilisé : Ceci est également de moins en moins vrai. Ce langage devient populaire outre-atlantique. La forge github répertorie le D en 25^ème position en terme de quantité de projet utilisant ce langage au sein de leur infrastructure. * En bêta : **Non** : le langage D est bel et bien stable et des améliorations périodiques sont mises à disposition. * Possède deux bibliothèques standard : **Non**, depuis plusieurs années la bibliothèque standard est _Phobos_, le pendant de la _STL_ + _Boost_ en C++ .

AltStyle によって変換されたページ (->オリジナル) /