Le langage D partie 1 : Différence entre versions

De Magazine fedora-fr
Aller à : navigation, rechercher
(Un exemple concret)
(Le langage D)
Ligne 5 : Ligne 5 :
  
 
===Introduction===
 
===Introduction===
Cette article propose de vous présenter un language un peu comme tous les autres mais, en c+=1. Soit, un peu comme tous les autres mais différent. Le D est un langage moderne et ce, pas seulement pour son jeune age (1999) il est aussi moderne par les nombreux conceptes et paradigmes qu'il permet de mettre en oeuvre. Le dossier consacré au D est découpé en une serie d'articles dont celui-ci est le premier. Chaque article couvrira une selection de domaines choisis.
+
Cette article propose de vous présenter un langage un peu comme tous les autres mais, en c+=1. Soit, un peu comme tous les autres mais différent. Le D est un langage moderne et ce, pas seulement pour son jeune age (1999) il est aussi moderne par les nombreux concepts et paradigmes qu'il permet de mettre en œuvre. Le dossier consacré au D est découpé en une série d'articles dont celui-ci est le premier. Chaque article couvrira une sélection de domaines choisis.
  
Ce premier article va introduire les bases du language et les outils minimaux dont vous avez besoins pour être capable de bien commencer et bien appréhender ce language. Les autres articles entrerons plus en details sur les notions avancées de développement avec ce language (Documentations, orienté objet, etc.).  
+
Ce premier article va introduire les bases du langage et les outils indispensables afin d'être capable de bien commencer et bien appréhender le D. Les autres articles entrerons plus en détails sur les notions avancées de développement (documentations, notion d'objet, etc.).  
  
Nous vous prévenons tous de suite, cette article est très orienté pratique mais, n'abandonne pas pour autant le coté théorique parfois inévitable. Cette approche représente en elle même la philosophie du language très orienté pratique mais reposant sur des conceptes théoriques necessaires. Cependant, les lecteurs avertis remarquerons très vite un ton d'écriture relativement légé et de très grosse dose de rappels de base en programmation sont présente dans cet article. Bien qu'ennuyer les programmeurs expérimentés soit une grande passions, la seconde raisons et de permettre au personnes peu expérimentées en programmation de pouvoir revoir certaines de leurs bases en cours de lecture de cet article. Il vous est maintenant fortement recomendé de laisser votre peur du changement, de la modernité et du pas comme tout le monde au vestiaire. Une fois ceci fais, nous vous souhaitons la bienvenue dans le monde merveilleux du D.
+
Nous vous prévenons tous de suite, cette article est truffé d'exemples et de cas concrets mais n'abandonne pas pour autant le coté théorique parfois inévitable. Cette approche représente en elle même la philosophie du langage D : orienté pratique mais reposant sur des concepts théoriques nécessaires.  
 +
Cet article reprend les principes de bases de la programmation tout en permettant de passer sur des notions déjà connues de certains.  
 +
Il vous est maintenant fortement recommandé de laisser votre peur du changement, de la modernité et du "pas comme tout le monde" au vestiaire.  
 +
Bienvenue dans le monde merveilleux du D.
  
Le langage D est un langage de programmation système qui se présente comme le successeur des langages C et C++ (Le succédait lui même du language B). Son objectif est d'allier la puissance du C et du C++ à la simplicité et à la productivité de langages comme Ruby et Python. Le célèbre slogan lié à ce langage est :
+
Le langage D est un langage de programmation système qui se présente comme le successeur des langages C et C++ (Le succédait lui même du langage B). Son objectif est d'allier la puissance du C et du C++ à la simplicité et à la productivité de langages comme Ruby et Python. Le célèbre slogan lié à ce langage est :
  
''Si un langage peut récupérer 90 % de la puissance du C++ mais seulement 10 % de sa complexité, cela vaut largement le coup.
+
''Si un langage peut récupérer 90 % de la puissance du C++ mais seulement 10 % de sa complexité, cela vaut largement le coup" de Walter Bright
 
+
Walter Bright''
+
  
 
Les paradigmes supportés par ce langage sont les suivants :
 
Les paradigmes supportés par ce langage sont les suivants :
Ligne 23 : Ligne 24 :
 
* programmation par contrat [http://fr.wikipedia.org/wiki/Programmation_par_contrat|4]
 
* programmation par contrat [http://fr.wikipedia.org/wiki/Programmation_par_contrat|4]
  
===Fedora 14===
+
===Fedora et le D===
La célèbre distribution Fedora garde un temps d'avance sur ses concurrentes. En effet, elle propose à ses utilisateurs un environnement de travail pour le langage D dernier cri. De nombreux jours de travail ont permis des améliorations significatives autour de ce langage. Et comme à son habitude, Fedora vous propose les dernières versions de ces outils. Avec un compilateur basé sur LLVM nommé ldc et une bibliothèque standard pour développer des applications en D : tango. Contrairement aux autres distributions, les outils sont pleinement fonctionnels et activement maintenus. De plus, le travail de la communauté Fedora ne s'est pas arrêté en si bon chemin. Celle-ci a également intégré :
+
La célèbre distribution Fedora garde un temps d'avance sur ses concurrentes. En effet, elle propose à ses utilisateurs un environnement de travail pour le langage D dernier cri. De nombreux jours de travail ont permis des améliorations significatives autour de ce langage. Et comme à son habitude, Fedora vous propose les dernières versions de ces outils. Avec un compilateur basé sur LLVM nommé ldc et une bibliothèque standard pour développer des applications en D : tango.
 +
Contrairement aux autres distributions, les outils sont pleinement fonctionnels et activement maintenus. De plus, le travail de la communauté Fedora ne s'est pas arrêté en si bon chemin. Celle-ci a également intégré :
 
* la bibliothèque mango qui tourne autour du réseau
 
* la bibliothèque mango qui tourne autour du réseau
 
* la bibliothèque derelict qui permet de développer des applications OpenGl en D
 
* la bibliothèque derelict qui permet de développer des applications OpenGl en D
Fedora c'est génial !
+
Si vous n'en étiez pas convaincu, au moins pour coder en D, Fedora c'est génial !
  
 
===À qui s'adresse ce langage ?===
 
===À qui s'adresse ce langage ?===
Ligne 82 : Ligne 84 :
 
Vous trouverez toutefois la procédure de mise en place ici : [http://www.youtube.com/watch?v=EBHQdpreTfk].
 
Vous trouverez toutefois la procédure de mise en place ici : [http://www.youtube.com/watch?v=EBHQdpreTfk].
  
A présent que notre équipement est paré, commençons par étudier les types de bases de ce language (brique essentiel en programmation).
+
A présent que notre équipement est paré, commençons par étudier les types de bases de ce langage (brique essentiel en programmation).
 
===Les types===
 
===Les types===
Comme tous language, le D possède des types. Ce chapitre se veux un résumé des principaux types disponibles pour ce merveilleux language.
+
Comme tous langage de programmation, le D possède des types. Ce chapitre se veut un résumé des principaux types disponibles.
  
 
Note 1 : les valeurs suivantes ont été obtenues sur un système 64 bits.
 
Note 1 : les valeurs suivantes ont été obtenues sur un système 64 bits.
Ligne 134 : Ligne 136 :
 
|}
 
|}
  
Armé de ces type, nous pouvons directement entrer dans le vif du sujet, c'est a dire vous faire créer votre premier programme en D.
+
Armé de ces types, nous pouvons directement entrer dans le vif du sujet, c'est a dire vous faire créer votre premier programme en D.
 
===Votre premier programme===
 
===Votre premier programme===
 
====Avant de commencer====
 
====Avant de commencer====
Ligne 192 : Ligne 194 :
  
 
=====Quelques explications=====
 
=====Quelques explications=====
Prenons quelques minute pour commenter ce code source précédemment crée.
+
Prenons un instant pour commenter ce code source précédemment créé.
  
 
* Sur la 1ère ligne, on indique que l'on a besoin du module Stdout se trouvant dans <path>tango/io/Stdout.d</path>.
 
* Sur la 1ère ligne, on indique que l'on a besoin du module Stdout se trouvant dans <path>tango/io/Stdout.d</path>.
Ligne 211 : Ligne 213 :
  
 
=====Les commentaires=====
 
=====Les commentaires=====
J'ai remarqué dans l'exemple précédent ''// j'imprime sur la sortie standard''. Qu'est ce que cela veut dire ?
+
Vous avez surement remarqué dans l'exemple précédent ''// j'imprime sur la sortie standard''. Qu'est ce que cela veut dire ?
 
Ceci est un commentaire. En effet, vous pouvez laisser des explications dans votre code  (c'est d'ailleurs très fortement recommandé). Il existe plusieurs formes de commentaires :
 
Ceci est un commentaire. En effet, vous pouvez laisser des explications dans votre code  (c'est d'ailleurs très fortement recommandé). Il existe plusieurs formes de commentaires :
  
Ligne 248 : Ligne 250 :
 
   +/
 
   +/
  
Vous remarquerez qu'il est parfois écrit « documentation » au lieu de « commentaire ». En effet, on peut documenter son code. Ainsi, un programme externe va lire votre code source et générer automatiquement la documentation. Pour les connaisseurs, c'est le même principe que Javadoc ou Doxygen.
+
Vous constaterez qu'il est parfois écrit « documentation » au lieu de « commentaire ». En effet, on peut documenter son code. Ainsi, un programme externe va lire votre code source et générer automatiquement la documentation. Pour les connaisseurs, c'est le même principe que Javadoc ou Doxygen.
  
 
Nous y reviendrons plus loin dans un futur article.
 
Nous y reviendrons plus loin dans un futur article.
  
Ce petit rappel extrêmement necessaire et impératif (les commentaires donc !) réalisé, passons en revue les outils de bases du language D.
+
Ce petit rappel extrêmement nécessaire et impératif (les commentaires donc !) réalisé, passons en revue les outils de bases du langage D.
  
 
===Les opérateurs arithmétiques===
 
===Les opérateurs arithmétiques===
Ligne 369 : Ligne 371 :
 
  jean is paul; // retournera faux
 
  jean is paul; // retournera faux
  
Lorsque l'on compare des objets entre eux (Un futur article entera plus en details sur ce sujet), ce comparateur va dire si oui ou non c'est le même objet qui est référencé.
+
Lorsque l'on compare des objets entre eux (un futur article entera plus en détails sur ce sujet), ce comparateur va indiquer si oui ou non c'est le même objet qui est référencé.
 
On reviendra plus tard sur les références, gardez-les à l'esprit et n'hésitez pas à revenir dessus.
 
On reviendra plus tard sur les références, gardez-les à l'esprit et n'hésitez pas à revenir dessus.
  
Ligne 452 : Ligne 454 :
 
# que le mot clé break soit absent
 
# que le mot clé break soit absent
  
D'après l'exemple précédent, on entrerait dans le bloc à partir du cas 3 et on effectuerait tous les cas suivants, c'est à dire ici le cas 4 et le cas par défaut. Dans la majeure partie des cas, on n'a pas besoin d'exécuter 2 règles, c'est pour cela que l'on met l'instruction break afin qu'il quitte après avoir effectué son traitement.
+
D'après l'exemple précédent, on entrerait dans le bloc à partir du cas 3 et on effectuerait tous les cas suivants, c'est à dire ici le cas 4 et le cas par défaut. Dans la majeure partie des cas, nous n'avons pas besoin d'exécuter 2 règles, c'est pour cela qu'est renseignée l'instruction break afin qu'il quitte après avoir effectué son traitement.
 
Un dernier exemple du même type pour la route :
 
Un dernier exemple du même type pour la route :
 
  int a = 1;
 
  int a = 1;
Ligne 469 : Ligne 471 :
 
         …
 
         …
 
  }
 
  }
Ici, on va rentrer dans le cas 1, 2 et 3 puis sortir.
+
Ici, nous entrons dans le cas 1, 2 et 3 puis sortir.
  
Ce comportement est similaire en C et en C++. Mais en D, on peut également utiliser des chaînes de caractères :
+
Ce comportement est similaire en C et en C++. Mais en D, il est également possible d'utiliser des chaînes de caractères :
 
  char[] prenom = "jonathan";
 
  char[] prenom = "jonathan";
 
  switch (prenom){ // on met la variable à tester
 
  switch (prenom){ // on met la variable à tester
Ligne 490 : Ligne 492 :
 
  }
 
  }
  
Maintenon, attaquons les tableaux.
+
Maintenant, attaquons les tableaux.
 
===Les tableaux===
 
===Les tableaux===
 
====Déclaration====
 
====Déclaration====
Ligne 523 : Ligne 525 :
 
====Les tableaux dynamiques====
 
====Les tableaux dynamiques====
 
  int[] a;
 
  int[] a;
Un tableau dynamique est un tableau dont la taille peut varier. Lors de sa déclaration, on ne spécifie pas sa taille. En fait, c'est le ramasse-miette (garbage collector) qui gère  ce tableau au moyen d'un pointeur.
+
Un tableau dynamique est un tableau dont la taille peut varier. Lors de sa déclaration, inutile de spécifier sa taille. En fait, c'est le ramasse-miette (garbage collector) qui gère  ce tableau au moyen d'un pointeur.
 
=====Exemples=====
 
=====Exemples=====
 
  int[] a;
 
  int[] a;
Ligne 536 : Ligne 538 :
 
  a[6] = 1;
 
  a[6] = 1;
  
Il est conseillé de faire le minimum possible de redimensionnements de tableaux  afin de garder de bonnes performances. Ainsi, on évitera :
+
Il est conseillé de faire le minimum possible de redimensionnements de tableaux  afin de garder de bonnes performances. Ainsi, nous éviterons :
 
  int[] a;
 
  int[] a;
 
  for ( i = 0 , i < 50, i++){
 
  for ( i = 0 , i < 50, i++){
Ligne 543 : Ligne 545 :
 
  }
 
  }
  
On utilisera de préférence :
+
et préférerons :
 
  int[] a;
 
  int[] a;
 
  for ( i = 0 , i < 50, i++){
 
  for ( i = 0 , i < 50, i++){
 
     if (a.length == i){
 
     if (a.length == i){
         a.length = a.length * 2; // si la taille du tableau est égale à l'indice i, on double sa taille;
+
         a.length = a.length * 2; // si la taille du tableau est égale à l'indice i, doublons sa taille;
 
     }
 
     }
 
     a = 0;
 
     a = 0;
 
  }
 
  }
  a.length = i; // Afin d'économiser de la mémoire, on ajuste exactement la taille du tableau au besoin soit la valeur de l'indice i
+
  a.length = i; // Afin d'économiser de la mémoire, il faut ajuster exactement la taille du tableau au besoin soit la valeur de l'indice i
  
Passons maintenant en revue un concept interessant, les tableaux associatifs.
+
Passons maintenant en revue un concept intéressant, les tableaux associatifs.
 
====Les tableaux associatifs====
 
====Les tableaux associatifs====
 
  int[char[]] x;
 
  int[char[]] x;
Un tableau associatif est un tableau dans lequel on associe 2 valeurs ensemble. Ici, on associe une chaîne de caractères à un entier.
+
Un tableau associatif est un tableau dans lequel on associe 2 valeurs ensemble. Ici, nous associons une chaîne de caractères à un entier.
  
Astuce: pour comprendre ce que que représente un tableau associatif, je vous conseille de le lire de la droite vers la gauche. Soit :
+
Astuce : pour comprendre ce que que représente un tableau associatif, je vous conseille de le lire de la droite vers la gauche. Soit :
  
 
Le tableau associatif x contient des chaînes de caractères qui sont associées à un entier.
 
Le tableau associatif x contient des chaînes de caractères qui sont associées à un entier.
Ligne 567 : Ligne 569 :
 
  x["orange"] = 7;
 
  x["orange"] = 7;
  
Dans l'exemple ci-dessus, on associe un fruit à un nombre (pratique pour connaître la quantité restante de chaque fruit).
+
Dans l'exemple ci-dessus,un fruit est associé à un nombre (pratique pour connaître la quantité restante de chaque fruit).
  
 
A présent que nous savons créer et utiliser des tableaux voyons qu'elles informations ils peuvent nous donner d'eux même à l'aide de leurs propriétés.
 
A présent que nous savons créer et utiliser des tableaux voyons qu'elles informations ils peuvent nous donner d'eux même à l'aide de leurs propriétés.
Ligne 606 : Ligne 608 :
 
|}
 
|}
  
Les prochains chapitres s'interesses à des aspects plus techniques mais utiles de la manipulation de tableaux.
+
Les prochains chapitres s’intéresse à des aspects plus techniques mais utiles de la manipulation de tableaux.
 
====Le slicing====
 
====Le slicing====
 
Le slicing est une technique particulière qui permet de copier une série d'éléments d'un tableau dans un autre. Voici un exemple de cette technique :
 
Le slicing est une technique particulière qui permet de copier une série d'éléments d'un tableau dans un autre. Voici un exemple de cette technique :
Ligne 677 : Ligne 679 :
 
  u = \n; // un retour à la ligne est assigné à u
 
  u = \n; // un retour à la ligne est assigné à u
 
   
 
   
Nous avons vu dans un chapitre précédent un rapide aperçu des tableaux associatifs nous allons maintenant nous interessé plus en détail à ceux-ci.
+
Nous avons vu dans un chapitre précédent un rapide aperçu des tableaux associatifs nous allons maintenant nous intéresser plus en détail à ceux-ci.
 
====Les tableaux associatifs====
 
====Les tableaux associatifs====
 
Le langage D intègre nativement les tableaux associatifs. Précédemment, vous avez eu un court exemple de leur utilisation. Voici quelques autres exemples :
 
Le langage D intègre nativement les tableaux associatifs. Précédemment, vous avez eu un court exemple de leur utilisation. Voici quelques autres exemples :
Ligne 701 : Ligne 703 :
 
|}
 
|}
  
L'erreur la plus frequente dans la manipulation de tableau est certainement leur dépassement, comment donc D gère t'il ceci ? Réponse dans la suite de cette article.
+
L'erreur la plus fréquente dans la manipulation de tableau est certainement leur dépassement. Comment le D gère-t-il ceci ? Réponse dans la suite de cette article.
 
====Dépassement de la taille du tableau====
 
====Dépassement de la taille du tableau====
 
Le dépassement de la taille limite du tableau constitue une erreur fréquemment rencontrée.  Le compilateur vous annoncera « Array index out of bounds ». Vous apprendrez plus loin comment attraper et gérer les exceptions.
 
Le dépassement de la taille limite du tableau constitue une erreur fréquemment rencontrée.  Le compilateur vous annoncera « Array index out of bounds ». Vous apprendrez plus loin comment attraper et gérer les exceptions.
Ligne 709 : Ligne 711 :
 
Qu'est-ce que cela veut dire ?
 
Qu'est-ce que cela veut dire ?
  
Pour faire simple, une référence est une entité qui pointe vers son original. Si l'on modifie la référence, cela modifie l'original. C'est un comportement qui permet d'éviter de recopier un tableau (ce qui peut être long) mais qui, si l'on ne fait pas attention, peut générer des erreurs. Gardez bien cela à l'esprit, c'est '''capital''' !
+
Pour faire simple, une référence est une entité qui pointe vers son original. Si la référence est modifiée, cela modifie l'original. C'est un comportement qui permet d'éviter de recopier un tableau (ce qui peut être long) mais qui, si l'on ne fait pas attention, peut générer des erreurs. Gardez bien cela à l'esprit, c'est '''capital''' !
  
 
Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :
 
Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :
Ligne 760 : Ligne 762 :
 
  int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a
 
  int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a
  
Nous avons maintenant des types de données et des tableaux, mais, un language ne serait rien sans les boucles. Le prochain chapitre s'interesse à cette notion et passe en revue les boucles en D.
+
Nous avons maintenant des types de données et des tableaux, mais un langage ne serait rien sans les boucles. Le prochain chapitre abordera cette notion et passera en revue les boucles en D.
 
===Les boucles===
 
===Les boucles===
 
====Tant que (while)====
 
====Tant que (while)====
Ligne 773 : Ligne 775 :
 
     }
 
     }
 
  }
 
  }
Tant que i est plus petit que 10, on boucle et on imprime sur la sortie standard la valeur courante de i.
+
Tant que i est plus petit que 10, on boucle et la valeur courante de i est envoyée sur la sortie standard.
 
====Faire tant que (do … while)====
 
====Faire tant que (do … while)====
Cette boucle est semblable à la précédente, seulement ici on garantit au moins une fois le passage dans la boucle.
+
Cette boucle est semblable à la précédente, seulement ici le passage dans la boucle au moins une fois est garanti.
 
  import tango.io.Stdout
 
  import tango.io.Stdout
 
  void main()
 
  void main()
Ligne 787 : Ligne 789 :
 
  }
 
  }
 
====Pour (for)====
 
====Pour (for)====
On peut effectuer la déclaration d'une variable, définir les conditions de la boucle et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable) dans la déclaration de la boucle for :
+
Il est possible d'effectuer la déclaration d'une variable, définir les conditions de la boucle et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable) dans la déclaration de la boucle for :
 
  for (uint i = 0; i < 10; ++i)
 
  for (uint i = 0; i < 10; ++i)
 
  {
 
  {
Ligne 798 : Ligne 800 :
 
       Stdout(element).nl;
 
       Stdout(element).nl;
 
  }
 
  }
Pour chaque élément de a, on imprime sa valeur sur la sortie standard.
+
Pour chaque élément de a, sa valeur est renvoyée sur la sortie standard.
  
On peut également connaître le nombre d'itérations dans la boucle foreach. Par exemple, connaître le numéro de ligne ou l'indice du tableau en cours de traitement.
+
Nous pouvons également connaître le nombre d'itérations dans la boucle foreach. Par exemple, connaître le numéro de ligne ou l'indice du tableau en cours de traitement.
 
  uint[5] a = [1,5,4,6,8];
 
  uint[5] a = [1,5,4,6,8];
 
  foreach(compteur,element;a) // Notons que element est de même type que a, ici de type uint[]  
 
  foreach(compteur,element;a) // Notons que element est de même type que a, ici de type uint[]  
Ligne 807 : Ligne 809 :
 
  }
 
  }
  
Et maintenant, juste pour faire hérisser de poiles, un chapitre tangent.
+
Et maintenant, juste pour faire hérisser de poils, un chapitre tangent.
 
====Aller à (goto)====
 
====Aller à (goto)====
 
Le goto n'est à utiliser que dans des cas précis. Il ne faut surtout pas en abuser et la plupart du temps les autres types de boucles suffisent. Depuis le temps que je programme je n'ai eu à l'utiliser qu'une seule fois.
 
Le goto n'est à utiliser que dans des cas précis. Il ne faut surtout pas en abuser et la plupart du temps les autres types de boucles suffisent. Depuis le temps que je programme je n'ai eu à l'utiliser qu'une seule fois.
Ligne 845 : Ligne 847 :
 
  double f = cast(double)(b);
 
  double f = cast(double)(b);
  
On utilise le module Convert uniquement pour utiliser le template "to" (le mot clé cast n'a besoin d'aucun module).
+
Le module Convert est employé uniquement pour utiliser le template "to" (le mot clé cast n'a besoin d'aucun module).
  
 
===Lire les entrées clavier===
 
===Lire les entrées clavier===
Ligne 871 : Ligne 873 :
 
  }
 
  }
  
On doit convertir ce qui a été saisi par l'utilisateur (char[]) en uint.
+
Nous devons convertir ce qui a été saisi par l'utilisateur (char[]) en uint.
  
 
Nous savons maintenant créer des programmes de base mais, comment créer un outil si nous n'avons aucn moyen d'interagire avec ? La suite de cette article s'interessera à la récupération des arguments passer par la ligne de commandes.
 
Nous savons maintenant créer des programmes de base mais, comment créer un outil si nous n'avons aucn moyen d'interagire avec ? La suite de cette article s'interessera à la récupération des arguments passer par la ligne de commandes.
Ligne 982 : Ligne 984 :
 
  }
 
  }
 
===Conclusion===
 
===Conclusion===
Nous voici à maintenant à la fin de cette première partie. Vous trouvez que c'est allé vite, ne vous inquiété pas, nous garderons le rythme pour les futures articles autour du D !
+
Nous voici à maintenant à la fin de cette première partie. Vous trouvez que c'est allé vite, ne vous inquiétez pas, nous garderons le rythme pour les futurs articles concernant le D !
  
Dans cette article avons passé en revue les conceptes fondamentaux permettant de construire un logiciel simple en D. Les prochains articles traitants de ce fantastique language permettrons aux lecteurs d'entrer plus en profondeur dans la puissance de ce language.
+
Dans cet article avons passé en revue les concepts fondamentaux permettant de construire un logiciel simple en D. Les prochains permettrons aux lecteurs d'entrer plus en profondeur dans la puissance de ce langage.
  
Mais, en attendant et à l'aide de ces concepts présentés, nous recommandons de vous entrainer et de créer vos premières applications.
+
En attendant, nous vous recommandons de vous entrainer et de créer vos premières applications.
  
  

Version du 18 mai 2011 à 16:40

Par : JonathanMercier
Article en cours de relecture !
InProgress tip.png
Le présent article est actuellement en cours de relecture.
Adressez-vous à la personne en charge pour toute proposition ou modification.
Relecteur / Validateur : [[Utilisateur:{{{1}}}|{{{1}}}]]

Sommaire

Le langage D

Introduction

Cette article propose de vous présenter un langage un peu comme tous les autres mais, en c+=1. Soit, un peu comme tous les autres mais différent. Le D est un langage moderne et ce, pas seulement pour son jeune age (1999) il est aussi moderne par les nombreux concepts et paradigmes qu'il permet de mettre en œuvre. Le dossier consacré au D est découpé en une série d'articles dont celui-ci est le premier. Chaque article couvrira une sélection de domaines choisis.

Ce premier article va introduire les bases du langage et les outils indispensables afin d'être capable de bien commencer et bien appréhender le D. Les autres articles entrerons plus en détails sur les notions avancées de développement (documentations, notion d'objet, etc.).

Nous vous prévenons tous de suite, cette article est truffé d'exemples et de cas concrets mais n'abandonne pas pour autant le coté théorique parfois inévitable. Cette approche représente en elle même la philosophie du langage D : orienté pratique mais reposant sur des concepts théoriques nécessaires. Cet article reprend les principes de bases de la programmation tout en permettant de passer sur des notions déjà connues de certains. Il vous est maintenant fortement recommandé de laisser votre peur du changement, de la modernité et du "pas comme tout le monde" au vestiaire. Bienvenue dans le monde merveilleux du D.

Le langage D est un langage de programmation système qui se présente comme le successeur des langages C et C++ (Le succédait lui même du langage B). Son objectif est d'allier la puissance du C et du C++ à la simplicité et à la productivité de langages comme Ruby et Python. Le célèbre slogan lié à ce langage est :

Si un langage peut récupérer 90 % de la puissance du C++ mais seulement 10 % de sa complexité, cela vaut largement le coup" de Walter Bright

Les paradigmes supportés par ce langage sont les suivants :

  • impératif [1]
  • orienté objet [2]
  • méta-programmation [3]
  • programmation par contrat [4]

Fedora et le D

La célèbre distribution Fedora garde un temps d'avance sur ses concurrentes. En effet, elle propose à ses utilisateurs un environnement de travail pour le langage D dernier cri. De nombreux jours de travail ont permis des améliorations significatives autour de ce langage. Et comme à son habitude, Fedora vous propose les dernières versions de ces outils. Avec un compilateur basé sur LLVM nommé ldc et une bibliothèque standard pour développer des applications en D : tango. Contrairement aux autres distributions, les outils sont pleinement fonctionnels et activement maintenus. De plus, le travail de la communauté Fedora ne s'est pas arrêté en si bon chemin. Celle-ci a également intégré :

  • la bibliothèque mango qui tourne autour du réseau
  • la bibliothèque derelict qui permet de développer des applications OpenGl en D

Si vous n'en étiez pas convaincu, au moins pour coder en D, Fedora c'est génial !

À qui s'adresse ce langage ?

  • Aux programmeurs qui sont lassés d'utiliser des analyseurs de codes ou des outils similaires pour réussir à éliminer des bogues.
  • À tout ceux qui en ont assez des messages d'erreur incompréhensibles lors de la compilation de code C++.
  • À tout ceux qui veulent utiliser la programmation objet sans avoir la complexité du C++.
  • Aux codeurs qui aiment la puissance du C++ mais qui sont frustrés par le temps de débogage nécessaire.
  • À ceux qui veulent intégrer les tests unitaires et activer des sections de code en mode débogage.
  • Aux équipes qui écrivent des applications avec un million de lignes de code.
  • Aux développeurs qui pensent que le langage doit fournir suffisamment de fonctionnalités pour pallier la nécessité de continuer à manipuler les pointeurs.
  • Aux programmeurs qui ont besoin de manipulations avancées sur les nombres. Le langage D intègre de nombreuses fonctionnalités pour cela.
  • Aux équipes qui doivent écrire en partie leurs applications dans des langages de script comme Python et Ruby pour gagner du temps de développement.

À qui ne s'adresse pas ce langage ?

Aux puristes. D est un langage orienté pratique et non théorique, chaque fonctionnalité est pensée avec cet objectif plutôt qu'un idéal théorique. Par exemple, D est construit et fournit une sémantique de façon à éliminer la nécessité de l'utilisation des pointeurs pour les tâches ordinaires. Mais les pointeurs sont toujours là, parce que leur utilisation est parfois obligatoire.

Nous allons maintenant procédé à l'installation de l'environnement minimal pour réussir à développer en D.

Ce dont vous avez besoin

Voici les principaux éléments nécessaire à tous développeurs D en herbe.

  • Un compilateur :
# yum install ldc
  • La bibliothèque standard du langage D :
# yum install tango-devel

Soit en une seule commande :

# yum install ldc tango-devel

Posséder les outils pour créer des applications D c'est bien mais, pouvoir les écrire dans un environnement d'edition c'est mieux. Nous allons donc continuer par un petit tour d'horizon d'environnements choisis.

Les éditeurs pour développer en D

Emacs

Pour cela, vous avez besoin de ce fichier: Fichier pour ajouter le support D dans Emacs.

  1. Démarrez emacs, puis faites "ouvrir" ou "créer un fichier D".
  2. Tapez M-x (méta x soit alt + x).
  3. Entrez d-mode (valider avec la touche entrée).

Gedit

Il n'y a rien à faire, il reconnait nativement le langage D et active la coloration syntaxique.

Scite

Il possède lui aussi la coloration syntaxique. Petite particularité: l'explorateur de fichier possède un filtre pour les fichiers sources et ne considère pas les fichiers .d comme tels ! Par conséquent, vous ne pouvez pas les voir. Il suffit de permuter le filtre sur "tout fichier".

Vim

Ce célèbre éditeur n'a rien à envier à ses semblables et propose lui aussi nativement la coloration syntaxique pour le langage D.

Code::blocks

Cet IDE supporte le langage D et propose l'auto-complétion ainsi que quelques autres fonctionnalités. Malheureusement, il ne supporte pas encore le compilateur ldc.

Eclipse et le plugin Descent

À travers ce plugin, on retrouve le confort de l'utilisation d'un IDE supportant le langage D. Tout comme Code::blocks, il ne supporte pas nativement le compilateur ldc.

Vous trouverez toutefois la procédure de mise en place ici : [5].

A présent que notre équipement est paré, commençons par étudier les types de bases de ce langage (brique essentiel en programmation).

Les types

Comme tous langage de programmation, le D possède des types. Ce chapitre se veut un résumé des principaux types disponibles.

Note 1 : les valeurs suivantes ont été obtenues sur un système 64 bits.

Note 2 : vous pouvez générer ces résultats avec ce fichier Programme_D_pour_connaitre_la_taille_des_types

Type Description Min Max
byte Valeur entière sur 1 octet (8 bits) -128 127
ubyte Valeur entière positive sur 1 octet (8 bits) 0 255
short Valeur entière sur 2 octets (16 bits) -32768 32767
ushort Valeur entière positive sur 2 octets (16 bits) 0 65535
int Valeur entière sur 4 octets (32 bits) -2147483648 2147483647
uint Valeur entière positive sur 4 octets (32 bits) 0 4294967296
long Valeur entière sur 8 octets (64 bits) -9223372036854775808 9223372036854775807
ulong Valeur entière positive sur 8 octets (64 bits) 0 18446744073709551615
float Valeur numérique sur 4 octets (32 bits) 1.18e-38 3.40e+38
ifloat Valeur numérique imaginaire pure sur 4 octets (32 bits) 1.18e-38i 3.40e+38i
double Valeur numérique sur 8 octets (64 bits) 2.23e-308 1.80e+308
idouble Valeur numérique imaginaire pure sur 8 octets (64 bits) 2.23e-308i 1.80e+308i
real Le plus grand numérique supporté par le processeur soit 16 octets (128 bits) 3.36e-4932 1.19e+4932
ireal Le plus grand numérique supporté par le processeur soit 16 octets (128 bits) 3.36e-4932i 1.19e+4932
char Un caractère imprimable encodé en UTF-8 sur 1 octet (8bits) 0 255
wchar Un caractère imprimable encodé en UTF-16 sur 2 octets (16bits) 0 65535
dchar Un caractère imprimable encodé en UTF-32 sur 4 octets (32bits) 0 4294967293
cfloat Nombre complexe de 2 valeurs flottantes (float) 1.18e-38 +1.18e-38i -nan
cdouble Nombre complexe de 2 doubles 2.23e-308 +2.23e-308i 1.19e+4932
creal Nombre complexe réel 3.36e-4932 +3.36e-4932i 1.19e+4932

Armé de ces types, nous pouvons directement entrer dans le vif du sujet, c'est a dire vous faire créer votre premier programme en D.

Votre premier programme

Avant de commencer

Avant de commencer, vous devez savoir que tous les programmes doivent être composés d'un main.

Qu'est-ce que le main ?

Le main est la fonction principale du programme. Pour faire court, c'est le point de départ du programme.

Qu'est-ce qu'une fonction ?

Une fonction est composée des éléments suivants :

  1. un en-tête : celui-ci va faire office de carte d'identité de la fonction.
  2. un corps : le contenu de la fonction, c'est à dire ce qui est exécuté lors de l'appel de la fonction. Il est délimité par des accolades {}.
  3. une valeur de retour : le résultat que la fonction va retourner.

L'en-tête de la fonction main peut s'écrire de plusieurs manières. En voici quelques-unes :

  • une fonction principale retournant un entier et ne prenant pas d'argument
int main (){
…
}
  • une fonction principale retournant un entier et pouvant prendre des arguments de la ligne de commande
int main (char[][] args){
…
}
  • une fonction principale ne retournant aucune valeur et ne prenant pas d'argument
void main (char[][] args){
…
}

Bonjour le monde

Et oui, on ne va pas casser la tradition ! (Bon d'accord, j'ai francisé cette tradition.)

Un exemple simple

Je ne vais pas vous faire languir plus longtemps. Créez un fichier hello.d et écrivez-y les lignes de code suivantes :

import tango.io.Stdout;
void main(){
    Stdout("Bonjour le monde").nl;// j'imprime sur la sortie standard
}

Simple, vous ne trouvez pas ? Maintenant, compilons !

Compilation et exécution

Pour compiler, faites simplement :

$ ldc hello.d

Pour l'exécuter:

$ ./hello.d

Je vous laisse le plaisir d'observer le résultat.

Quelques explications

Prenons un instant pour commenter ce code source précédemment créé.

  • Sur la 1ère ligne, on indique que l'on a besoin du module Stdout se trouvant dans <path>tango/io/Stdout.d</path>.

Nous y reviendrons plus tard. Sachez simplement que tous les modules D que vous aurez installés sous Fedora sont dans <path>/usr/include/d/</path>.

Soit ici : <path>/usr/include/d/tango/io/Stdout.d</path>.

  • La 2ème ligne, vous l'aurez reconnue, est notre fonction principale. Elle ne prend pas d'argument et ne retourne aucune valeur.
  • La 3ème ligne est dans la fonction principale, (remarquez les {}) et demande d'écrire sur la sortie standard "Bonjour le monde" suivi d'un retour à la ligne (.nl pour new line/nouvelle ligne).

Il existe beaucoup de façons différentes d'écrire sur la sortie standard mais ne vous éparpillez pas ! On aurait pu souhaiter ne pas vouloir de retour à la ligne à la fin de notre phrase, cela se fait aussi simplement :

Stdout("Bonjour le monde");

Note: n'oubliez pas de recompiler votre code pour voir le changement.

  • La 4ème ligne vient fermer le bloc de la fonction principale.
Les commentaires

Vous avez surement remarqué dans l'exemple précédent // j'imprime sur la sortie standard. Qu'est ce que cela veut dire ? Ceci est un commentaire. En effet, vous pouvez laisser des explications dans votre code (c'est d'ailleurs très fortement recommandé). Il existe plusieurs formes de commentaires :

Commentaire sur une ligne

// Mon commentaire
/// Ceci est une documentation

Commentaire multi-lignes

/*
  Ceci est un commentaire
*/
/*
 * Ceci est un commentaire
 */
/+
  Ceci est un commentaire
+/
/+
 + Ceci est un commentaire
 +/
/**
  Ceci est une documentation
*/
/**
 * Ceci est une documentation
 */
/++
 + Ceci est une documentation
 +/

Vous constaterez qu'il est parfois écrit « documentation » au lieu de « commentaire ». En effet, on peut documenter son code. Ainsi, un programme externe va lire votre code source et générer automatiquement la documentation. Pour les connaisseurs, c'est le même principe que Javadoc ou Doxygen.

Nous y reviendrons plus loin dans un futur article.

Ce petit rappel extrêmement nécessaire et impératif (les commentaires donc !) réalisé, passons en revue les outils de bases du langage D.

Les opérateurs arithmétiques

+ permet d'additionner deux variables numériques. - permet de soustraire deux variables numériques. * permet de multiplier deux variables numériques. / permet de diviser deux variables numériques. % permet de renvoyer le reste de la division euclidienne de deux variables de type numérique ; cet opérateur s'appelle le modulo. Par exemple :

import tango.io.Stdout;
void main(){
    uint a = 2;
    uint b = 2;
    Stdout.formatln("une addition: {} + {} = {}", a, b, a+b);
    Stdout.formatln("une soustraction: {} - {} = {}", a, b, a-b);
    Stdout.formatln("une multiplication: {} x {} = {}", a, b, a*b);
    Stdout.formatln("une division: {} / {} = {}", a, b, a/b);
    Stdout.formatln("le modulo: {} % {} = {}", a, b, a%b);
}

Une histoire d'incrémentation et décrémentation

Dans la même catégorie, il existe l'incrémentation et la décrémentation :

  • l'incrémentation consiste à augmenter de 1 la valeur de la variable.
  • la décrémentation consiste à diminuer de 1 la valeur de la variable.

Pour cela, il y a plusieurs façons de le faire. Prenons le cas de l'incrémentation :

int a = 2;
a = a + 1;
a += 1;
a++;
++a

Vous remarquez que les 2 dernières formes sont plus rapides à écrire (oui, le programmeur est un fainéant).

Y a-t-il une différence entre ++a et a++ ?

Oui, il y en a une et elle est subtile :

  • a++ : utilise la valeur de a, puis l'incrémente
  • ++a: incrémente la valeur de a, puis l'utilise

Par exemple :

import tango.io.Stdout;
void main(){
    uint a = 2;
    Stdout.formatln("une incrémentation: {} + {} = {}", a, b, a++);
    a = 2;
    Stdout.formatln("une incrémentation: {} + {} = {}", a, b, ++a);
    a = 2;
    Stdout.formatln("une décrémentation: {} - {} = {}", a, b, a--);
    a = 2;
    Stdout.formatln("une décrémentation: {} - {} = {}", a, b, --a);
}

Autres raccourcis

On peut également utiliser les raccourcis pour la multiplication, la division et le reste de la division euclidienne. un court exemple :

uint a = 5;
a *= 2;
a /= 2;
a %= 2;

Attention

Je vous mets en garde sur le type utilisé. Ce dernier peut avoir des conséquences graves ! En effet, jusqu'ici on a utilisé le type uint et nos résultats étaient des entiers. Mais ceci n'est pas systématiquement vrai. Par exemple, diviser 1 par 3 donne un résultat décimal ne pouvant pas correspondre à un entier positif (uint). Par conséquent, vous devez utiliser un autre type plus approprié, comme le type float ou double :

double a = 1;
a /=3; // a vaut 0.33333333
int b = 1;
int c = 3;
double d = b / c; // d vaut 0.33333333

Les opérateurs de comparaison

Il est fréquent dans un programme que l'on ait de besoin de comparer. Pour cela, en D, il est possible de tester différents cas :

  • tester une égalité
3 == 3; // cette expression retournera vrai
3 == 4; // cette expression retournera faux

  • tester une différence
3 != a; // 3 est différent de 4 donc cette expression retournera vrai
  • comparer a ou b
a || b // si l'une des expressions est vraie, l'expression globale sera vraie
  • comparer a et b
a && b // si l'une des expressions est fausse, l'expression globale sera fausse
  • savoir si a est strictement plus petit que b
a < b
  • savoir si a est plus petit ou égal à que b
a <= b
  • savoir si a est strictement plus grand que b
a > b
  • savoir si a est plus grand ou égal à b
a >= b
  • savoir si a est identique à b
a is b
  • savoir si a n'est pas identique à b
a !== b

Notes

Les comparateurs d'identités sont particuliers et méritent plus d'explications. Si l'on compare :

  • des types entre eux (par exemple int)
int[1] a = 2;
int[1] b = a;
a is b; // retournera vrai

Lorsque l'on compare des types avec ce comparateur, il agit comme si c'était le comparateur ==

  • des objets
Personne jean = new Personne("jean");
Personne paul = new Personne("paul");
jean is paul; // retournera faux

Lorsque l'on compare des objets entre eux (un futur article entera plus en détails sur ce sujet), ce comparateur va indiquer si oui ou non c'est le même objet qui est référencé. On reviendra plus tard sur les références, gardez-les à l'esprit et n'hésitez pas à revenir dessus.

Le comparateur !== est la négation du comparateur === donc

Personne jean = new Personne("jean");
Personne paul = new Personne("paul");
jean !is paul; // retournera vrai

Les conditions

Dans le chapitre précédent, nous avons vu les opérateurs de comparaison. Maintenant, nous allons les utiliser avec les conditions. Rien de plus simple ! Commençons de suite.

Avec les mots clés if et else

int a = 2;
if ( a == 2 ){ // test une égalité avec l'opérateur == , si a vaut 2
    Stdout("la variable a vaut bien 2").nl;
}
else if ( a == 3){ // sinon si la variable a vaut 3
    Stdout("la variable a vaut bien 3").nl;
}
else{ // sinon (pour tous les autres cas)
    Stdout.formatln("la variable a vaut {}",a);
}

C'était un exemple pour vous dégourdir les méninges. Complexifions légèrement avec divers exemples d'utilisation :

int a = 2;
int b = 3;
if ( a == 2 && b == 3 ){ // si a vaut 2 et b vaut 3. Les 2 conditions doivent être vraies pour rentrer dans le bloc
    Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
}
if ( a == 2 || b ==3 ){ // si a vaut 2 ou bien si b vaut 3. Au moins une des 2 conditions doit être vraie pour rentrer dans le bloc
    Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
}
if ( a > 1 && b >= 3 ){ // si a est strictement plus grande que 1 et b plus grande ou égale à 3. Les 2 conditions doivent être vraies pour rentrer dans le bloc
    Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
}
if ( a <= 2 || b < 3){ // si a est plus petite ou égale à 2 ou bien si b est strictment plus petite que 3. Au moins une des 2 conditions doit être vraie pour rentrer dans le bloc
    Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
}

Avec les mots clés switch et case

Vous avez vu précédemment la possibilité d'imbriquer des si - sinon de la manière suivante :

int a = 4;
if ( a == 0){
…
}
else if ( a == 1){
…
}
else if ( a == 2){
…
}
else if ( a == 3){
…
}
else if ( a == 4){
…
}
else {
…
}

Sachez qu'il existe une manière plus élégante d'écrire cela à l'aide des mots clés switch et case :

int a = 4;
switch (a){ // on met la variable à tester
    case 1: // cas où la valeur est 1
        …
        break
    case 2: // cas où la valeur est 2
        …
        break
    case 3: // cas où la valeur est 3
        …
        break
    case 4: // cas où la valeur est 4
        …
        break
    default: // cas où la valeur est différente
        …
}

Un petit rappel au passage, savez-vous pourquoi retrouve-t-on break à chaque fois ? Admettons 2 choses pour imager:

  1. que la variable a vaut 3
  2. que le mot clé break soit absent

D'après l'exemple précédent, on entrerait dans le bloc à partir du cas 3 et on effectuerait tous les cas suivants, c'est à dire ici le cas 4 et le cas par défaut. Dans la majeure partie des cas, nous n'avons pas besoin d'exécuter 2 règles, c'est pour cela qu'est renseignée l'instruction break afin qu'il quitte après avoir effectué son traitement. Un dernier exemple du même type pour la route :

int a = 1;
switch (a){ // on met la variable à tester
    case 1: // cas où la valeur est 1
        …
    case 2: // cas où la valeur est 2
        …
    case 3: // cas où la valeur est 3
        …
        break
    case 4: // cas où la valeur est 4
        …
        break
    default: // cas où la valeur est différente
        …
}

Ici, nous entrons dans le cas 1, 2 et 3 puis sortir.

Ce comportement est similaire en C et en C++. Mais en D, il est également possible d'utiliser des chaînes de caractères :

char[] prenom = "jonathan";
switch (prenom){ // on met la variable à tester
    case "jonathan": // cas où la valeur est "jonathan"
        …
        break
    case "jean": // cas où la valeur est "jean"
        …
        break
    case "paul": // cas où la valeur est "paul"
        …
        break
    case "remi": // cas où la valeur est "remi"
        …
        break
    default: // cas où la valeur est différente
        …
}

Maintenant, attaquons les tableaux.

Les tableaux

Déclaration

Il y a 5 façons de déclarer un tableau (attention, pointeur inside :) !) :

Code Description
int* p; Pointeur vers les données
int[3] s; Tableau statique
int[] a; Tableau dynamique
int[char[]] x; Tableau associatif
int[][] m; Matrice

Les pointeurs

int* p;

Ceci est un simple pointeur vers des données, il représente la même chose qu'en C. Pour ces raisons, je vous invite à lire la partie La mémoire, une question d'adresse sur le Site du Zéro.

Les tableaux statiques

int[3] s;

Un tableau statique est un tableau dont on spécifie la taille lors de sa déclaration, taille qui ne changera plus. Ici, on crée un tableau dans lequel on peut stocker 3 entiers. La taille d'un tableau statique est fixée au moment de la compilation.

Exemples
int[3] s;
s[0] = 50;
s[1] = 24;
s[2] = 98;

Les tableaux dynamiques

int[] a;

Un tableau dynamique est un tableau dont la taille peut varier. Lors de sa déclaration, inutile de spécifier sa taille. En fait, c'est le ramasse-miette (garbage collector) qui gère ce tableau au moyen d'un pointeur.

Exemples
int[] a;
a.length = 2; // on donne une taille de 2
a[0] = 5;
a[1] = 8;
a.length = a.length + 5 // ici 2+5 = 7 soit la nouvelle taille du tableau
a[2] = 5;
a[3] = 7;
a[4] = 9;
a[5] = 3
a[6] = 1;

Il est conseillé de faire le minimum possible de redimensionnements de tableaux afin de garder de bonnes performances. Ainsi, nous éviterons :

int[] a;
for ( i = 0 , i < 50, i++){
    a.length = a.length + 1;
    a[i] = 0;
}

et préférerons :

int[] a;
for ( i = 0 , i < 50, i++){
    if (a.length == i){
        a.length = a.length * 2; // si la taille du tableau est égale à l'indice i, doublons sa taille;
    }
    a = 0;
}
a.length = i; // Afin d'économiser de la mémoire, il faut ajuster exactement la taille du tableau au besoin soit la valeur de l'indice i

Passons maintenant en revue un concept intéressant, les tableaux associatifs.

Les tableaux associatifs

int[char[]] x;

Un tableau associatif est un tableau dans lequel on associe 2 valeurs ensemble. Ici, nous associons une chaîne de caractères à un entier.

Astuce : pour comprendre ce que que représente un tableau associatif, je vous conseille de le lire de la droite vers la gauche. Soit :

Le tableau associatif x contient des chaînes de caractères qui sont associées à un entier.

Exemples
int[char[]] x;
x["pomme"] = 2;
x["poire"] = 5;
x["orange"] = 7;

Dans l'exemple ci-dessus,un fruit est associé à un nombre (pratique pour connaître la quantité restante de chaque fruit).

A présent que nous savons créer et utiliser des tableaux voyons qu'elles informations ils peuvent nous donner d'eux même à l'aide de leurs propriétés.

Les propriétés

Propriétés des tableaux statiques
Propriétés Descriptions
.sizeof Retourne la taille du tableau multipliée par le nombres d'octets pour chaque élément du tableau.
.length Retourne le nombre d'éléments dans le tableau. Cette valeur ne peut pas être modifiée pour les tableaux statiques.
.ptr Retourne un pointeur sur le premier élément du tableau.
.reverse Inverse l'ordre des éléments (le premier devient le dernier) et renvoie le tableau inversé.
.sort Trie les éléments du tableau et renvoie le tableau trié.
.dup Crée un tableau dynamique de la même taille et copie tous les éléments dans ce tableau puis renvoie ce tableau.
Propriétés des tableaux dynamiques
Propriétés Descriptions
.sizeof Retourne la taille de la référence du tableau dynamique, qui est de 8 sur un ordinateur 32 bits.
.length Permet d'obtenir ou de changer la taille du tableau.
.ptr Retourne un pointeur sur le premier élément du tableau.
.reverse Inverse l'ordre des éléments (le premier devient le dernier) et retourne le tableau inversé.
.sort Trie les éléments du tableau et renvoie le tableau trié.
.dup Crée un tableau dynamique de la même taille, et copie tous les éléments dans ce tableau puis retourne ce tableau.

Les prochains chapitres s’intéresse à des aspects plus techniques mais utiles de la manipulation de tableaux.

Le slicing

Le slicing est une technique particulière qui permet de copier une série d'éléments d'un tableau dans un autre. Voici un exemple de cette technique :

int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[] b; // déclare un tableau dynamique
int[] c; // déclare un tableau dynamique
int[3] d; // déclare un tableau statique de 3 éléments
b = a[1..3]; // le fameux slicing, on copie ici les éléments des indices 1 à 3 dans le tableau b. Rappel: le premier indice est le 0 a[0]
c = a[4..$]; // ici on copie tous les éléments à partir de l'indice 4 jusqu'à la fin
d[0..2] = 5; // ici on assigne la valeur 5 à tous les éléments du tableau. Cela équivaut à d[0] = 5 d[1] = 5 d[2] = 5

Concaténation de tableaux

int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[10] b = [11,12,13,14,15,16,17,18,19,20]; // déclare un tableau de 10 entiers
int[] c;
c = a ~ b; // soit c contient 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

On peut combiner le slicing et la concaténation

int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[10] b = [11,12,13,14,15,16,17,18,19,20]; // déclare un tableau de 10 entiers
int[] c;
c = a ~ b[0..5]; // soit c contient 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

Les matrices

Peu de langages supportent nativement les matrices, mais le langage D en fait partie.

Qu'est-ce qu'une matrice ?

Mieux qu'un long discours, voici un exemple :

0 0 0 
0 0 0 
0 0 0 
0 0 0 

Ceci est une matrice de 4 colonnes par 3 lignes :

uint[3][4] matrix; // déclaration de la matrice
foreach (ligne; matrix)
{
   ligne[0..$] = 0;// on remplit la matrice de 0 en utilisant le slicing, c'est pratique !
}

Les chaînes de caractères

Les langages de programmation doivent bien gérer les chaînes de caractères. Le C et le C++ ne sont pas très bons pour cela. La première difficulté est de gérer la mémoire, les traitements temporaires, de constamment scanner les chaînes de caractères pour rechercher la terminaison par "\0" et de fixer la taille.

Les tableaux dynamiques en D suggèrent la solution la plus évidente. Une chaîne est simplement un tableau dynamique de caractères. Les chaînes littérales sont juste un moyen facile d'écrire des tableaux de caractères.

char[] str = "Le D c'est génial"; // déclaration et initialisation
char[] str1 = str.dup; // copie de la chaîne de caractères
str += " et je l'ai adopté"; // on ajoute à la suite de la chaîne str
char str2[] = "Vive le D";
char str3 = str ~ str2; // on concatène str et str2, grâce au ~ et on stocke le tableau résultant dans str3

Par défaut les chaînes de caractère sont encodées en utf8. Il existe également les types:

  • wchar
  • wchar[]
  • dchar
  • dchar[]

Si une chaîne est ambiguë et peut correspondre à plusieurs types, il faut préciser.

Si on veut de l'UTF-32, on peut faire un cast (voir « Les conversions de type (cast) ») :

(wchar [])"J'aime le D";

Ou si on veut de l'UTF-32 : 
(dchar[])"J'aime le D";
char c;
wchar u;
dchar a;
c = "b"; // le caractère b (UTF-8) est assigné à c
u = "b" // le caractère b (UTF-16) est assigné à u
a = "b" // le caractère b (UTF-32) est assigné à a
u = \n; // un retour à la ligne est assigné à u

Nous avons vu dans un chapitre précédent un rapide aperçu des tableaux associatifs nous allons maintenant nous intéresser plus en détail à ceux-ci.

Les tableaux associatifs

Le langage D intègre nativement les tableaux associatifs. Précédemment, vous avez eu un court exemple de leur utilisation. Voici quelques autres exemples :

int[char[]] b; // association d'une chaîne de caractère à un entier
b["pomme"] = 3 // on met 3 pommes
uint nombre =  b["pomme"]; // renvoie le nombre de pommes
delete  b["pomme"]; // on supprime la clé "pomme"
Propriété
Propriétés Descriptions
.sizeof Renvoie la taille de la référence vers le tableau associatif.
.length Renvoie le nombre de valeurs dans le tableau associatif. À la différence des tableaux dynamiques, on ne peut pas changer sa valeur.
.keys Renvoie un tableau dynamique contenant les clés du tableau associatif.
.values Renvoie un tableau dynamique contenant les valeurs du tableau associatif.
.rehash Réorganise le tableau associatif pour gagner en performance. Retourne une référence du tableau réorganisé.

L'erreur la plus fréquente dans la manipulation de tableau est certainement leur dépassement. Comment le D gère-t-il ceci ? Réponse dans la suite de cette article.

Dépassement de la taille du tableau

Le dépassement de la taille limite du tableau constitue une erreur fréquemment rencontrée. Le compilateur vous annoncera « Array index out of bounds ». Vous apprendrez plus loin comment attraper et gérer les exceptions.

Important

En D comme dans d'autres langages tels que le Python, les tableaux et les objets sont passés par référence et non par copie.

Qu'est-ce que cela veut dire ?

Pour faire simple, une référence est une entité qui pointe vers son original. Si la référence est modifiée, cela modifie l'original. C'est un comportement qui permet d'éviter de recopier un tableau (ce qui peut être long) mais qui, si l'on ne fait pas attention, peut générer des erreurs. Gardez bien cela à l'esprit, c'est capital !

Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :

int [5] a = 3; // les 5 colonnes valent 3
int [] b = a; // b est une référence de a, si je modifie b le tableau a sera modifié
int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a
Exemple
import tango.io.Stdout;

void ajoute(uint nombre, uint[] tableau)
{
    foreach(indice,element;tableau){
        tableau[indice] = element + nombre;
    }
}
void main()
{
    uint[] montableau = [1,2,3,4,5,6];
    ajoute(2, montableau);
    Stdout(montableau).nl;
}

Vous voyez que votre tableau a été modifié à votre insu vous avez sur le terminal:

[3, 4, 5, 6, 7, 8]

Vous vous retrouvez avec le tableau modifié par la fonction ajoute. Si vous ne voulez pas ce comportement, vous devez envoyer une copie du tableau. Voici un exemple:

 import tango.io.Stdout;

void ajoute(uint nombre, uint[] tableau)
{
    foreach(indice,element;tableau){
        tableau[indice] = element + nombre;
    }
}
void main()
{
    uint[] montableau = [1,2,3,4,5,6];
    ajoute(2, montableau.dup);
    Stdout(montableau).nl;
}

Ce qui donne:

[1, 2, 3, 4, 5, 6]


Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :

int [5] a = 3; // les 5 colonnes valent 3
int [] b = a; // b est une référence de a, si je modifie b le tableau a sera modifié
int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a

Nous avons maintenant des types de données et des tableaux, mais un langage ne serait rien sans les boucles. Le prochain chapitre abordera cette notion et passera en revue les boucles en D.

Les boucles

Tant que (while)

import tango.io.Stdout
void main()
{
    uint = 0;
    while (i < 10)
    {
        Stdout(i).nl;
        i++;
    }
}

Tant que i est plus petit que 10, on boucle et la valeur courante de i est envoyée sur la sortie standard.

Faire tant que (do … while)

Cette boucle est semblable à la précédente, seulement ici le passage dans la boucle au moins une fois est garanti.

import tango.io.Stdout
void main()
{
    uint i = 10;
    do{
        Stdout(i).nl;
        i++;
    }
    while(i < 10)
}

Pour (for)

Il est possible d'effectuer la déclaration d'une variable, définir les conditions de la boucle et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable) dans la déclaration de la boucle for :

for (uint i = 0; i < 10; ++i)
{
    Stdout(i).nl;
}

Pour chaque (foreach)

uint[5] a = [1,5,4,6,8];
foreach(element;a)
{
     Stdout(element).nl;
}

Pour chaque élément de a, sa valeur est renvoyée sur la sortie standard.

Nous pouvons également connaître le nombre d'itérations dans la boucle foreach. Par exemple, connaître le numéro de ligne ou l'indice du tableau en cours de traitement.

uint[5] a = [1,5,4,6,8];
foreach(compteur,element;a) // Notons que element est de même type que a, ici de type uint[] 
{
     Stdout.formatln("numéro {} valeur {}",compteur, element);
}

Et maintenant, juste pour faire hérisser de poils, un chapitre tangent.

Aller à (goto)

Le goto n'est à utiliser que dans des cas précis. Il ne faut surtout pas en abuser et la plupart du temps les autres types de boucles suffisent. Depuis le temps que je programme je n'ai eu à l'utiliser qu'une seule fois. Le goto permet d'aller directement à un endroit du code défini par une étiquette :

import tango.io.Stdout;

void main()
{
    uint i = 0;
    Stdout("Bonjour").nl;
    monEtiquette:
    i++;
    Stdout.formatln("Valeur de i {}", i);
    if ( i < 2 )
    {
        goto monEtiquette;
    }
    Stdout("Fin").nl;
}

Comme tous les language typé, le D propose des solutions pour transformer les données d'un type à l'autre. Le prochain chapitre s'interesse à ce sujet.

Les conversions de type (cast)

En langage D, il existe 2 manières d'effectuer une conversion de type :

  • avec le mot clé cast
  • avec le module tango.util.Convert

La première façon de faire est générique et permet de caster (convertir) tout et n'importe quoi. C'est l'équivalent du dynamic_cast pour les connaisseurs du C++. La seconde manière est restreinte au type cité dans un chapitre précédent mais est plus sûre. Exemples :

import module tango.util.Convert;
short a = 1;
float b = 0.5;
int c = to!(int)(a); // on utilise le template nommé "to" provenant du module Convert et on spécifie le type int
int d = cast(int)a; 
double e = to!(double)(b); // on utilise le template nommé "to" provenant du module Convert et on spécifie le type double
double f = cast(double)(b);

Le module Convert est employé uniquement pour utiliser le template "to" (le mot clé cast n'a besoin d'aucun module).

Lire les entrées clavier

import tango.io.Console;

void main()
{
    Cout("Entrer votre nom: ")();
    char[] nom = Cin.get;
    Cout("Salut ")(nom).newline;
}

Demander le nom et l'âge:

import tango.io.Console;
import tango.util.Convert;
import tango.io.Stdout;

void main()
{
    Cout("Entrer votre nom: ")();
    char[] nom = Cin.get;
    Cout("Entrer votre age: ")();
    uint age = to!(uint)(Cin.get);
    Stdout.formatln("Salut {} tu as donc {} ans", nom , age);    
}

Nous devons convertir ce qui a été saisi par l'utilisateur (char[]) en uint.

Nous savons maintenant créer des programmes de base mais, comment créer un outil si nous n'avons aucn moyen d'interagire avec ? La suite de cette article s'interessera à la récupération des arguments passer par la ligne de commandes.

Parser les arguments de la ligne de commande

La bibliothèque tango propose un module très pratique pour parser les arguments de la ligne de commande. Il existe un tutoriel en anglais ici. Je vais vous présenter la manière dont je l'utilise au travers d'un exemple relativement simple:

import text.Arguments  : Arguments;
import tango.io.Stdout : Stdout, Stderr;
import tango.text.Regex: Regex;
import monApplication.Parser;
bool verbose = false;
const float numVersion = 0.1;
void verboseMode(char[] message)
{
    if (verbose)
        Stdout.formatln("\033[0;31m'{}'\033[0;0m",message);
}
void about()
{
    Stdout.formatln("monApplication version \033[0;31m'{}'\033[0;0m", numVersion);
    Stdout.formatln("monApplication est un super programme écrit en D.");
}
void usage(Arguments getopt)
{
    Stdout.formatln("\033[0;31mUsage:\033[0;0m ./monApplication [options] --input files");
    Stdout.formatln("Options:");
    getopt.help((char[] param, char[] text){Stdout.format("\t--{}    {}\n",param, text);});
}
int main (char[][] args)
{
    char[] inputFile;
    char[] outputFile;
    
    /**
     * Définit les options du programme
     */
    auto getopt = new Arguments;
    getopt("help").params(0).aliased('h').help("- Display this message");
    getopt("verbose").params(0).aliased('v').help("- Enable verbose mode");
    getopt("input").params(1).aliased('i').help("- Path to input file");
    getopt("output").params(1).aliased('o').help("- Path to output file");
    getopt("version").params(0).help("- Display metatool version");
    /**
     * Parse la ligne de commande
     */
     getopt.parse(args);
     /**
      * Active ou non le mode verbeux
      */
    if (getopt("verbose").set)
    {
        verbose = true;
    }
    /**
     * Affiche l'aide si demandé
     */
    if (getopt("help").set)
    {
        usage(getopt);
    }
    /**
     * Affiche la version si demandée
     */
    else if (getopt("version").set)
    {
        about();
    }
    /**
     * Affiche un message d'erreur et quitte le programme si l'option --input n'est pas presente
     */
    else if (!getopt("input").set)
    {
        Stderr.formatln("\033[0;31mWarning:\033[0;0m option --input absent!");
        usage(getopt);
        scope(failure) Stderr.formatln("Programme arrêté subitement");
    }
    else{
        /**
         * Stocke le nom du fichier soumis par l'option --input
         */
        inputFile = getopt("input").assigned[0];
        verboseMode("Input file: "~inputFile);

        /**
         * Stocke le nom du fichier soumis par l'option  --output
         */
        if (getopt("output").set){
            outputFile = getopt("output").assigned[0];
        }
        else{ // Si l'option --output est absente, il prend le nom du fichier "input" et remplace l'extention par .out
            auto filePattern= new Regex(r"\.[a-zA-Z0-9_]+");
            if (filePattern.test(inputFile)){
                outputFile = filePattern.replaceLast(inputFile,".out");
            }
            else{
                outputFile = inputFile ~ ".out";
            }
        }
        verboseMode("Output file: "~outputFile);
        /**
         * Parse le fichier input
         */
        auto parser = new Parser(inputFile);
        parser.parse();
        parser.check();
        
    }
    scope(exit) Stdout.formatln("quit");
    scope(success) Stdout.formatln("Programme se termine avec succès");
    return 1;
}

Conclusion

Nous voici à maintenant à la fin de cette première partie. Vous trouvez que c'est allé vite, ne vous inquiétez pas, nous garderons le rythme pour les futurs articles concernant le D !

Dans cet article avons passé en revue les concepts fondamentaux permettant de construire un logiciel simple en D. Les prochains permettrons aux lecteurs d'entrer plus en profondeur dans la puissance de ce langage.

En attendant, nous vous recommandons de vous entrainer et de créer vos premières applications.


À voir aussi

  • La documentation de l' API tango.
  • exemple et tutorial autour de la bibliothèque tango.
  • Le site tango : [6].
  • Le livre incontournable à mettre dans toutes les mains: [7].
  • Les ressources de digital mars: [8].
  • Les spécifications du langage D version d1.
  • Une documentation en français du langage D en pdf et en html.
  • Suivez les avancées du livre et de la documentation autour du D sur le wikibook que j'ai moi-même rédigé.
  • Présent également sur irc serveur freenode :
    • le chan #d
    • le chan #d.tango
    • le chan #ldc

Remerciements

Je remercie tous les membres de l'équipe du magazine Muffin pour leur aide et l'intégration de cette serie articles dans le magazine. Mais également :

  • misc pour m'avoir fait découvrir gobby et m'avoir aidé à la relecture.
  • trashy pour sa participation à la relecture.
  • paulk pour ses remarques avisées et sa contribution à la relecture.
  • djezael pour son sens de l'orthographe et ses tournures de phrases.
  • Eyyub d'avoir testé tous les exemples et d'avoir comblé certains points noirs.