Fedora-Fr - Communauté francophone Fedora - Linux

Planet de Fedora-Fr : la communauté francophone autour de la distribution Linux Fedora

A propos

Cette page est actualisée toutes les heures.

Cette page est une sélection de blogs autour de Fedora. Fedora-Fr.org décline toute responsabilité au sujet des propos tenus par les auteurs des blogs de ce planet. Leurs propos sont leur entière responsabilité.

Le contenu de ce planet appartient à leurs auteurs respectifs. Merci de consulter leur blogs pour obtenir les licences respectives.

Mot-clefs : D programming

dustmite un outil qui vous fait gagner du temps

Jonathan Mercier

Cher lecteur,

Cette article concerne les développeurs. En effet combien de fois on s'est arraché les cheveux à essayé de comprendre pourquoi son application segfault.Ceci c'est terminé avec dustmite!

Cet outil va réduire le code jusquà généré un code minimaliste provoquant l'erreur. Cet outil fonctionne pour le langage D et il peut être étendu à d'autres langages. Le projet à juste besoin de vous :-)" class="smiley . dustmite sera fourni à partir de fedora 17 dans les dépôts officiels.

Fichier core


  1. $ ulimit -c unlimited

Dans un premier temps il faut autoriser la création de fichier core lorsqu'un programme segfault

Espace de travail


  1. $ mkdir workdir

Ensuite on créer un répertoire dans le quel dustmite travaillera

Très originale comme nom de dossier :-D" class="smiley

Sources

Ensuite on va mettre les fichiers app.d et utild.d dans le dossier workdir. C'est le programme qui va planter :-D" class="smiley


  1. import std.string;
  2. import std.stdio;
  3.  
  4. import util;
  5.  
  6. void main( ){
  7. A* a = null;
  8. *a = A( [2uL, 3uL, 4uL] );
  9. (*a).append( 5u );
  10. writeln( (*a).length );
  11. if( (*a).length > 3 )
  12. a = null;
  13. writeln( (*a).length );
  14. (*a).append( 0u );
  15. writeln( (*a).length );
  16. }

app.d


  1. module util;
  2.  
  3. struct A{
  4. size_t[] items;
  5. size_t length;
  6.  
  7. this( size_t[] items ){
  8. this.items = items;
  9. this.length = items.length;
  10. }
  11.  
  12. void append( size_t item ){
  13. this.items ~= item;
  14. }
  15. }

utild.d

Compilation


  1. $ (cd workdir && ldc2 app.d util.d -of=app && rm *.o)

Compilation du programme.

Note: j'ai supprimé les fichier .o généré cat ceux ci peuvent géner plus loin dustmite

Génération du fichier core


  1. $ (cd workdir && ./app )

Éxécutons le programme, il va générer un fichier core:

DustMite


  1. $ DustMite workdir/ "(ldc2 app.d util.d -ofapp && ./app) 2>&1| grep -qF 'Segmentation fault'"

Maintenant il reste plus qua dustmite de nous dire pourquoi le programme segfault

Ici plusieurs chose importante:

  1. spécifier a dustmite le dossier de travail
  2. il faut donner la commande de construction a dustmite => ldc2 app.d util.d -ofapp
  3. lui dire comment lancer l'appilcation => ./app
  4. ne pas oublier les parenthèses ()
  5. fusionner la sortie d'erreur sur la sortie standard =>2>&1
  6. dustmite récupère la sortie par conséquent il faut filtrer via grep sur notre segfault. (attention ici la locale utilisé est C donc penser a mettre le bon motif dans votre commande grep

Ainsi dustmite peut faire son travail

$ DustMite workdir/ "(ldc2 app.d util.d -ofapp  && ./app)  2>&1| grep -qF 'Segmentation fault'"
None => Yes
############### ITERATION 0 ################
============= Depth 0 =============
Remove [1/4] => Yes
Remove [1/3] => No
Remove [2/3] => Yes
Remove [2/2] => No
############### ITERATION 1 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/2] => Yes
Remove [1/2, 1/1] => No
Remove [2/2, 1/4] => Yes
Remove [2/2, 1/3] => No
Remove [2/2, 2/3] => No
Remove [2/2, 3/3] => No
############### ITERATION 2 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => No (cached)
Remove [2/2, 2/3] => No (cached)
Remove [2/2, 3/3] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/3, 1/1] => No
Remove [2/2, 2/3, 1/1] => No
Remove [2/2, 3/3, 1/2] => No
Remove [2/2, 3/3, 2/2] => No
Unwrap [2/2, 3/3, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/4] => No
Remove [1/2, 1/1, 2/2, 2/4] => No
Remove [1/2, 1/1, 2/2, 3/4] => Yes
Remove [1/2, 1/1, 2/2, 3/3] => No
Remove [2/2, 3/3, 1/2, 1/2] => No
Remove [2/2, 3/3, 1/2, 2/2] => No
Unwrap [2/2, 3/3, 1/2, 2/2] => No (cached)
Remove [2/2, 3/3, 2/2, 1/8] => No
Remove [2/2, 3/3, 2/2, 2/8] => No
Remove [2/2, 3/3, 2/2, 3/8] => Yes
Remove [2/2, 3/3, 2/2, 3/7] => Yes
Remove [2/2, 3/3, 2/2, 3/6] => Yes
Remove [2/2, 3/3, 2/2, 3/5] => Yes
Remove [2/2, 3/3, 2/2, 3/4] => Yes
Remove [2/2, 3/3, 2/2, 3/3] => Yes
############### ITERATION 3 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => Yes
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
############### ITERATION 4 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No (cached)
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/3] => No
Remove [1/2, 1/1, 2/2, 2/3] => Yes
Remove [1/2, 1/1, 2/2, 2/2] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 5 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => No
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1] => No
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 2/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
============= Depth 6 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No
Unwrap [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2, 1/1] => Yes
############### ITERATION 6 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 7 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No (cached)
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No (cached)
============= Depth 6 =============
Done in 7 secs and 18 ms; reduced version is in workdir.reduced

Le résultat du code minimaliste provoquant l'erreur est dans le dossier workdir.reduced


  1. $ ls workdir.reduced
  2. app.d util.d

Contenu des fichiers:


  1. import util;
  2.  
  3. void main( ){
  4. A* a = null;
  5. *a = A( );
  6. }

app.d


  1. struct A{
  2. }

util.d

dustmite nous montre que le segfault provient de l'utilisation d'un pointeur nulle. Le code ici est écrit à la façon C (avec des pointeurs) pour provoquer un segfault. La plupart du temps en D vous n'avez pas besoin des pointeurs mais utiliserez les références (simple et transparent). En effet le code utiliser ce veux pédagogique pour l'utilisation de dustmite ;-)" class="smiley .

dustmite un outil qui vous fait gagner du temps

Jonathan Mercier

Cher lecteur,

Cette article concerne les développeurs. En effet combien de fois on s'est arraché les cheveux à essayé de comprendre pourquoi son application segfault.Ceci c'est terminé avec dustmite!

Cet outil va réduire le code jusquà généré un code minimaliste provoquant l'erreur. Cet outil fonctionne pour le langage D et il peut être étendu à d'autres langages. Le projet à juste besoin de vous :-)" class="smiley . dustmite sera fourni à partir de fedora 17 dans les dépôts officiels.

Fichier core


  1. $ ulimit -c unlimited

Dans un premier temps il faut autoriser la création de fichier core lorsqu'un programme segfault

Espace de travail


  1. $ mkdir workdir

Ensuite on créer un répertoire dans le quel dustmite travaillera

Très originale comme nom de dossier :-D" class="smiley

Sources

Ensuite on va mettre les fichiers app.d et utild.d dans le dossier workdir. C'est le programme qui va planter :-D" class="smiley


  1. import std.string;
  2. import std.stdio;
  3.  
  4. import util;
  5.  
  6. void main( ){
  7. A* a = null;
  8. *a = A( [2uL, 3uL, 4uL] );
  9. (*a).append( 5u );
  10. writeln( (*a).length );
  11. if( (*a).length > 3 )
  12. a = null;
  13. writeln( (*a).length );
  14. (*a).append( 0u );
  15. writeln( (*a).length );
  16. }

app.d


  1. module util;
  2.  
  3. struct A{
  4. size_t[] items;
  5. size_t length;
  6.  
  7. this( size_t[] items ){
  8. this.items = items;
  9. this.length = items.length;
  10. }
  11.  
  12. void append( size_t item ){
  13. this.items ~= item;
  14. }
  15. }

utild.d

Compilation


  1. $ (cd workdir && ldc2 app.d util.d -of=app && rm *.o)

Compilation du programme.

Note: j'ai supprimé les fichier .o généré cat ceux ci peuvent géner plus loin dustmite

Génération du fichier core


  1. $ (cd workdir && ./app )

Éxécutons le programme, il va générer un fichier core:

DustMite


  1. $ DustMite workdir/ "(ldc2 app.d util.d -ofapp && ./app) 2>&1| grep -qF 'Segmentation fault'"

Maintenant il reste plus qua dustmite de nous dire pourquoi le programme segfault

Ici plusieurs chose importante:

  1. spécifier a dustmite le dossier de travail
  2. il faut donner la commande de construction a dustmite => ldc2 app.d util.d -ofapp
  3. lui dire comment lancer l'appilcation => ./app
  4. ne pas oublier les parenthèses ()
  5. fusionner la sortie d'erreur sur la sortie standard =>2>&1
  6. dustmite récupère la sortie par conséquent il faut filtrer via grep sur notre segfault. (attention ici la locale utilisé est C donc penser a mettre le bon motif dans votre commande grep

Ainsi dustmite peut faire son travail

$ DustMite workdir/ "(ldc2 app.d util.d -ofapp  && ./app)  2>&1| grep -qF 'Segmentation fault'"
None => Yes
############### ITERATION 0 ################
============= Depth 0 =============
Remove [1/4] => Yes
Remove [1/3] => No
Remove [2/3] => Yes
Remove [2/2] => No
############### ITERATION 1 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/2] => Yes
Remove [1/2, 1/1] => No
Remove [2/2, 1/4] => Yes
Remove [2/2, 1/3] => No
Remove [2/2, 2/3] => No
Remove [2/2, 3/3] => No
############### ITERATION 2 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => No (cached)
Remove [2/2, 2/3] => No (cached)
Remove [2/2, 3/3] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/3, 1/1] => No
Remove [2/2, 2/3, 1/1] => No
Remove [2/2, 3/3, 1/2] => No
Remove [2/2, 3/3, 2/2] => No
Unwrap [2/2, 3/3, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/4] => No
Remove [1/2, 1/1, 2/2, 2/4] => No
Remove [1/2, 1/1, 2/2, 3/4] => Yes
Remove [1/2, 1/1, 2/2, 3/3] => No
Remove [2/2, 3/3, 1/2, 1/2] => No
Remove [2/2, 3/3, 1/2, 2/2] => No
Unwrap [2/2, 3/3, 1/2, 2/2] => No (cached)
Remove [2/2, 3/3, 2/2, 1/8] => No
Remove [2/2, 3/3, 2/2, 2/8] => No
Remove [2/2, 3/3, 2/2, 3/8] => Yes
Remove [2/2, 3/3, 2/2, 3/7] => Yes
Remove [2/2, 3/3, 2/2, 3/6] => Yes
Remove [2/2, 3/3, 2/2, 3/5] => Yes
Remove [2/2, 3/3, 2/2, 3/4] => Yes
Remove [2/2, 3/3, 2/2, 3/3] => Yes
############### ITERATION 3 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => Yes
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
############### ITERATION 4 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No (cached)
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/3] => No
Remove [1/2, 1/1, 2/2, 2/3] => Yes
Remove [1/2, 1/1, 2/2, 2/2] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 5 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => No
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1] => No
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 2/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
============= Depth 6 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No
Unwrap [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2, 1/1] => Yes
############### ITERATION 6 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 7 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No (cached)
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No (cached)
============= Depth 6 =============
Done in 7 secs and 18 ms; reduced version is in workdir.reduced

Le résultat du code minimaliste provoquant l'erreur est dans le dossier workdir.reduced


  1. $ ls workdir.reduced
  2. app.d util.d

Contenu des fichiers:


  1. import util;
  2.  
  3. void main( ){
  4. A* a = null;
  5. *a = A( );
  6. }

app.d


  1. struct A{
  2. }

util.d

dustmite nous montre que le segfault provient de l'utilisation d'un pointeur nulle. Le code ici est écrit à la façon C (avec des pointeurs) pour provoquer un segfault. La plupart du temps en D vous n'avez pas besoin des pointeurs mais utiliserez les références (simple et transparent). En effet, le code présenté se veut pédagogique pour l'utilisation de dustmite ;-)" class="smiley .

D programming version D2

Jonathan Mercier

Chèr lecteur,

Me voici de retour sur le langage D dans sa version 2. Je vais tenter ici de vous apprendre à programmer progressivement. En effet je considère que le langage D est un très bon langage, même pour un débutant. Il existe deux écoles sur ce sujet, ceux préconisant l'apprentissage par un langage de programmation:

  1. haut niveau tel que python
  2. bas niveau tel que le C

La première école a le mérite d'offrir au futur programmeur des progrès rapide au détriment de notion importante sur le fonctionnement de l'ordinateur, les mauvaises habitudes de programmations à éviter, où encore l'enfermement dans un langage ( triste ). La seconde école nécessite une plus grande volonté pour le débutant afin d'arriver à ces fins, mais ceci lui donne l'aptitude de mieux comprendre comment est traduit son programme par l'ordinateur, une plus grande capacité pour apprendre de nouveaux langages.

Le langage java pourrait concilier les 2 écoles mais la compréhension de la programmation orientée objet est un obstacle trop important. Mais voilà le langage D qui vient chambouler cet état. En effet le langage D offre le compromis idéale en simplicité pour lapprentissage de la programmation. Sur cette courte introduction nous allons commencer à apprendre le langage D. Pour cela vous devez installer les outils nécessaires:

  • ldc, compilateur D
  • pobos, la bibliothèque standard
  • druntime, le ramasse miette
$ su -c 'yum install ldc ldc-druntime ldc-druntime-devel ldc-phobos ldc-phobos-devel'

Je vous conseil en plus (optionnel):

  • ldc-phobos-geany-tags, pour l'auto-complétion dans geany
  • ldc-phobos-devhelp, pour avoir une petite doc de l'api de phobos
$ su -c 'yum install ldc-phobos-geany-tags ldc-phobos-devhelp'

Premier pas

Quel outil utiliser ?

Pour écrire du code en langage D je préconise dans l'ordre:

  1. geany
  2. scite
  3. gedit

D'autres outil existe mais ils ne feront pas l'objet de ce chapitre.

Écrire un message dans la console (sortie standard )

A l'aide de votre éditeur préféré ( geany pour moi :-D" class="smiley )


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. write( "Bonjour :-)" );
  6. }

Compilation

Geany

Il suffit d'appuyer sur F8 ;-)" class="smiley

Ligne de commande
$ ldc2 test.d

Exécution

Geany

Il suffit d'appuyer sur F5 ;-)" class="smiley

Ligne de commande
$ ./test
Bonjour :-)" class="smiley

Explication du programme

Afin d'écrire sur la console on doit utiliser la fonction write, cette fonction est définit dans le module std.stdio.

Deuxièmement pour utiliser les chaines de caractères on doit utiliser le type string définit dans le module std.string.

la troisième ligne définit la fonction principale du programme, la fonction main. C'est le point de départ du programme. La fonction main peut recevoir les paramètres de la lignes de commandes. Ces paramètres sont stocké dans le tableau qui se nomme args. Nous verront tout ça plus loin juste retenez que la fonction principale s'écrit de cette manière. Le contenu de la fonction principale est définit par { }. C'est à dire que toutes lignes entre { } de la fonction main seront exécuté ( évalué pour faire du vocabulaire :-)" class="smiley ). Notre fonction principale ne contient qu'une seule ligne write( "Bonjour :-)" ); qui permet d'écrire bonjour dans la console.

Faire une addition

On va faire une simple addition, pour cela comme précédemment on va importer de quoi écrire sur la console et écrire la fonction de départ la fonction main.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. write( "2 + 3 = " );
  6. write( 2 + 3 );
  7. }

Compilation et Exécution

Exactement comme précédemment, je vous renvoie donc au point d'avant. Le résultat:

$ ./test
2 + 3 = 5

Explication du programme

Le programme principale commence par écrire dans la console la chaine de caractère 2 + 3 = la seconde ligne écrit à la suite le résultat de l'addition 2 + 3 soit 5 :-)" class="smiley

Les type késako ???

On a tous appris tout petit ce qu'est un type mais on a vite oublié tellement que c'est évident :-)" class="smiley . Oui oui rappelez vous les chiffres 1, 2, 3 sont des entiers et 2.5 est un chiffre décimal ( flottant ). L'ordinateur fait comme nous, la distinction entre les différents types voici de suite un exemple


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. int chiffre1 = 2;
  6. int chiffre2 = 3;
  7. write( "2 + 3 = " );
  8. write( chiffre1 + chiffre2 );
  9. }

Alors ce programme fait exactement la même chose que le précédent, c'est à dire qu'il fait l'addition de 2 + 3 :-)" class="smiley .

Ici on a stocké la valeur de 2 dans la variable chiffre1 de type entier, la valeur de 3 stocké dans la variable chiffre2 de type entier. Un entier c'est un chiffre positif ou négatif, si vous n'utilisez que des entiers positif je vous conseil d'utiliser le type size_t.

Information complémentaire: pour les connaisseurs size_t agit comme le type uint sauf qu'il s'adapte aux architectures selon que l'on compile sur un ordinateur 32 bits (uint) ou 64 bits (ulong) de façon automatique.

Faire une fonction

Il est important de découper notre programme en différente fonction. En effet celà permet de ne pa réécrire, par exemple le code effectuant une addition à chaque fois. Le code pour ce travail est écrit une fois et ensuite on l'apelle au besoin. Concrètement cela se traduit par :


  1. import std.stdio;
  2. import std.string;
  3.  
  4. size_t addition( size_t a, size_t b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. size_t chiffre1 = 2;
  10. size_t chiffre2 = 3;
  11. size_t resultat = addition( chiffre1, chiffre2)
  12. write( "2 + 3 = " );
  13. write( resultat );
  14. }

Ici on a définit une fonction qui sappelle addition. Elle prends deux paramètres qui seront stocké respectivement dans a et b. Ces paramètres doivent êtres des entiers positifs car ils sont typé size_t. Enfin la fontion retourne une valeur de type size_t car avant le nom de la fonction il est écrit size_t.

Surcharger une fonctions

C'est bien jolie la fonction addition! Mais moi, je voudrais additionner des types différents! C'est simple il suffit d'écrire les fonctions avec les type désirés.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. size_t addition( size_t a, size_t b){
  5. return a + b ;
  6. }
  7.  
  8. float addition( size_t a, float b){
  9. return a + b ;
  10. }
  11.  
  12. double addition( double a, size_t b){
  13. return a + b ;
  14. }
  15.  
  16. double addition( double a, double b){
  17. return a + b ;
  18. }
  19.  
  20. void main( string[] args ){
  21. float chiffre1 = 2.6;
  22. size_t chiffre2 = 3;
  23. double chiffre3 = 5;
  24. float resultat1 = addition( chiffre2, chiffre1);
  25. size_t resultat2 = addition( chiffre2, chiffre2);
  26. double resultat3 = addition( chiffre3, chiffre2);
  27. double resultat4 = addition( chiffre3, chiffre3);
  28. }

Le compilateur choisira la fonction addition correspondant aux types soumis. Le nom de la fonction suivie de ces paramètres forme la signature de la fonction. Le type de retour n'est pas compris dans la signature.

Les templates

Les fonctions ne permettent pas d'écrire en une fois "une addition c'est comme ça quelque soit le type"! est là qu'intervient les templates pour écrire des fonctions génériques.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. T addition(T,U)( T a, U b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. float chiffre1 = 2.6;
  10. size_t chiffre2 = 3;
  11. float resultat = addition( chiffre1, chiffre2);
  12. write( "2.6 + 3 = " );
  13. write( resultat );
  14. }

Dans notre Exemple le template retournera toujours le même type que le type du prmier paramètre. Ainsi si on inverse l'ordre des paramètres chiffre1 et chiffre2 , le résultat sera de type size_t et donc tronqué (pas de chiffre après la virgule)

Un moyen simple de résoudre ce soucis et de simplement laisser le compilateur de déterminer automatiquement le type de retour. soit simplement:


  1. import std.stdio;
  2. import std.string;
  3.  
  4. auto addition(T,U)( T a, U b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. float chiffre1 = 2.6;
  10. size_t chiffre2 = 3;
  11. float resultat = addition( chiffre1, chiffre2);
  12. write( "2.6 + 3 = " );
  13. write( resultat );
  14. }

La seule modification est l'utilisation du mot clé auto.

Les commentaires

Afin de documenter ton code est pouvoir le comprendre facilement on peut ajouter des commentaires dans le code qui ne seront pas évalué par le compilateur. Un exemple vaut mieux qu'un long discours.


  1. // je suis un commentaire sur une ligne
  2. /*
  3.  je suis un commentaire
  4.  sur plusieurs ligne
  5.  */

Les tableaux

Lorsque l'on développe des applications on utilisent souvent les tableaux. Un tableau va permettre de stocker une suite d'information.


  1. int[] tableau = [1, 2, 3];

On a définit une variable tableau de type int, les signifie que c'est un tableau d'int. Pour accéder au premier élément on commence à compter à partir de 0.


  1. int[] tableau = [1, 2, 3];
  2. writeln( tableau[0] );

Slicing

On peut également récupérer une portion du tableau, par exemple on souhaite récupérer les élément à partir de l'indice 2 jusquà la fin:


  1. int[] tableau1 = [1, 2, 3];
  2. int[] tableau2 = tableau1[ 2 .. $];
  3. writeln( tableau2 );

Le symbole $ indique la fin du tableau, si l'on veut l'avant dernier élément on peut faire $ - 1 et ainsi des suite. La longueur d'un tableau peut être connu de cette façon.

Longueur de tableau


  1. int[] tableau1 = [1, 2, 3];
  2. writeln( tableau1.length );

On peut changer la taille d'un tableau:


  1. int[] tableau1 = [1, 2, 3];
  2. tableau1.length = tableau1.length + 5;
  3. tableau1[2 .. $] = [ 4, 5, 6, 7, 8 ];

Concatenation

Pour joindre deux tableaux on utilise le caractère ~


  1. int[] tableau1 = [1, 2, 3];
  2. tableau1 ~= [ 4, 5, 6, 7, 8 ];

Les boucles

Tant que (while)


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint = 0;
  5. while (i < 10){
  6. writeln(i);
  7. i++;
  8. }
  9. }

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

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.


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint i = 10;
  5. do{
  6. writeln(i);
  7. i++;
  8. }
  9. while(i < 10);
  10. }

Pour (for)

On peut effectuer la déclaration d'une variabl (uint i = 0;)e, définir les conditions de la boucle ( i < 10) et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable, comme ici: ++i) ,dans la déclaration de la boucle for :


  1. for (uint i = 0; i < 10; ++i){
  2. writeln(i);
  3. }

Pour chaque (foreach)


  1. uint[5] a = [1,5,4,6,8];
  2. foreach(element;a){
  3. writeln(element);
  4. }

Pour chaque élément de a, on imprime sa valeur 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.


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

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 :


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint i = 0;
  5. writeln("Bonjour");
  6. monEtiquette:
  7. i++;
  8. writefln("Valeur de i %d", i);
  9. if ( i < 2 ){
  10. goto monEtiquette;
  11. }
  12. writeln("Fin");
  13. }

Les chaines de caractères

Afin d'utiliser les chaines de( caractères, vous devez utiliser le module std.string. Une chaine de caractère commence et se termine par le symbole ", alors qu'un caractère commence et se termine par le symbole '. Soit:


  1. import std.string;
  2.  
  3. string maChaine = "je suis une chaine de caractère supportant l'unicode sans rien faire.";
  4. char caractere = 'c';

Les variables de type string sont immutables cela signigifie que le prochain chapitre, le lire, tu devras (yoda).

Les constantes

Le langage D différentie deux types de constante, const et immutable. const est utilisé pour dire que l'adresse de la variable x ne changera pas. immutable est utilisé pour dire que la valeur de la variable ne changera pas.

le mot clé const renvoie à la notion de pointeur et de référence. l'utilisation des pointeurs en D et pour moi est utile uniquement dans un but de faire une interface d'une application C.

Un peu de code:


  1. immutable int pi = 3.14; // la variable pi ne peut changer de valeur
  2. immutable int[] tableaux = [ 1, 2, 3 ]; // on ne peut pas modifier le contenu du tableau
  3. immutable int[1] tableaux = 4; // erreur on ne peut pas changer la valeur du tableau
  4. immutable int[] tableaux = [ 1, 4, 3]; // mais on peut donner une nouvelle référence

Le type string est immutable par conséquent on ne peut pas faire ça:


  1. string chaine = "Le langage C c'est cool";
  2. chaine[11] = 'D'; // -> Error: chaine[11] isn't mutable

pour cela on fait comme ça:


  1. string chaine = "Le langage C c'est cool";
  2. chaine = chaine[0 .. 11] ~ 'C' ~ [12 .. $];

La différence ici est que l'on change la référence assigner à la variable chaine. Dans un premier temps on construit le tableau de caractère "Le langage D c'est cool" et la référence de ce tableau est assigné à la variable chaine.

D programming version D2

Jonathan Mercier

Cher lecteur,

Me voici de retour sur le langage D dans sa version 2. Je vais tenter ici de vous apprendre à programmer progressivement. En effet je considère que le langage D est un très bon langage, même pour un débutant. Il existe deux écoles sur ce sujet, ceux préconisant l'apprentissage par un langage de programmation:

  1. haut niveau tel que python
  2. bas niveau tel que le C

La première école a le mérite d'offrir au futur programmeur des progrès rapide au détriment de notion importante sur le fonctionnement de l'ordinateur, les mauvaises habitudes de programmations à éviter, où encore l'enfermement dans un langage ( triste ). La seconde école nécessite une plus grande volonté pour le débutant afin d'arriver à ces fins, mais ceci lui donne l'aptitude de mieux comprendre comment est traduit son programme par l'ordinateur, une plus grande capacité pour apprendre de nouveaux langages.

Le langage java pourrait concilier les 2 écoles mais la compréhension de la programmation orientée objet est un obstacle trop important. Mais voilà le langage D qui vient chambouler cet état. En effet le langage D offre le compromis idéale en simplicité pour lapprentissage de la programmation. Sur cette courte introduction nous allons commencer à apprendre le langage D. Pour cela vous devez installer les outils nécessaires:

  • ldc, compilateur D
  • pobos, la bibliothèque standard
  • druntime, le ramasse miette
$ su -c 'yum install ldc ldc-druntime ldc-druntime-devel ldc-phobos ldc-phobos-devel'

Je vous conseil en plus (optionnel):

  • ldc-phobos-geany-tags, pour l'auto-complétion dans geany
  • ldc-phobos-devhelp, pour avoir une petite doc de l'api de phobos
$ su -c 'yum install ldc-phobos-geany-tags ldc-phobos-devhelp'

Pour fedora 16 seulement

Pour les personnes souhaitant utilisé le langage D sous Fedora 16 je leur conseil d'installer le dépôt D: . Celui ci corrige de nombreux soucis, en effet il m'est dans l'impossibilité de fournir une mise a jour pour fedora 16 due a des soucis avec llvm-2.9 ceci est corrigé dans fedora-17 ou via le dépôt pour fedora 16

Premier pas

Quel outil utiliser ?

Pour écrire du code en langage D je préconise dans l'ordre:

  1. geany
  2. scite
  3. gedit

Geany

Changer le compilateur D a utiliser: construire->definir les commandes de construction Remplacer seulement dmd par ldc2 et c'est tout :-)" class="smiley .

D'autres outil existe mais ils ne feront pas l'objet de ce chapitre.

Écrire un message dans la console (sortie standard )

A l'aide de votre éditeur préféré ( geany pour moi :-D" class="smiley )


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. write( "Bonjour :-)" );
  6. }

Compilation

Geany

Il suffit d'appuyer sur F8 ;-)" class="smiley

Ligne de commande
$ ldc2 test.d

Exécution

Geany

Il suffit d'appuyer sur F5 ;-)" class="smiley

Ligne de commande
$ ./test
Bonjour :-)

Explication du programme

Afin d'écrire sur la console on doit utiliser la fonction write, cette fonction est définit dans le module std.stdio.

Deuxièmement pour utiliser les chaines de caractères on doit utiliser le type string définit dans le module std.string.

la troisième ligne définit la fonction principale du programme, la fonction main. C'est le point de départ du programme. La fonction main peut recevoir les paramètres de la lignes de commandes. Ces paramètres sont stocké dans le tableau qui se nomme args. Nous verront tout ça plus loin juste retenez que la fonction principale s'écrit de cette manière. Le contenu de la fonction principale est définit par { }. C'est à dire que toutes lignes entre { } de la fonction main seront exécuté ( évalué pour faire du vocabulaire :-)" class="smiley ). Notre fonction principale ne contient qu'une seule ligne write( "Bonjour :-)" ); qui permet d'écrire bonjour dans la console. Note: write écrit sur la même ligne si vous souhaiter un retour à la ligne utiliser writeln.

Faire une addition

On va faire une simple addition, pour cela comme précédemment on va importer de quoi écrire sur la console et écrire la fonction de départ la fonction main.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. write( "2 + 3 = " );
  6. write( 2 + 3 );
  7. }

Compilation et Exécution

Exactement comme précédemment, je vous renvoie donc au point d'avant. Le résultat:

$ ./test
2 + 3 = 5

Explication du programme

Le programme principale commence par écrire dans la console la chaine de caractère 2 + 3 = la seconde ligne écrit à la suite le résultat de l'addition 2 + 3 soit 5 :-)" class="smiley .

Les types késako ???

On a tous appris tout petit ce qu'est un type mais on a vite oublié tellement que c'est évident :-)" class="smiley . Oui oui rappelez vous les chiffres 1, 2, 3 sont des entiers et 2.5 est un chiffre décimal ( flottant ). L'ordinateur fait comme nous, la distinction entre les différents types voici de suite un exemple


  1. import std.stdio;
  2. import std.string;
  3.  
  4. void main( string[] args ){
  5. int chiffre1 = 2;
  6. int chiffre2 = 3;
  7. write( "2 + 3 = " );
  8. write( chiffre1 + chiffre2 );
  9. }

Alors ce programme fait exactement la même chose que le précédent, c'est à dire qu'il fait l'addition de 2 + 3 :-)" class="smiley .

Ici on a stocké la valeur de 2 dans la variable chiffre1 de type entier, la valeur de 3 stocké dans la variable chiffre2 de type entier. Un entier c'est un chiffre positif ou négatif, si vous n'utilisez que des entiers positif je vous conseil d'utiliser le type size_t.

Information complémentaire: pour les connaisseurs size_t agit comme le type uint sauf qu'il s'adapte aux architectures selon que l'on compile sur un ordinateur 32 bits (uint) ou 64 bits (ulong) de façon automatique.

Faire une fonction

Il est important de découper notre programme en différente fonction. En effet celà permet de ne pa réécrire, par exemple le code effectuant une addition à chaque fois. Le code pour ce travail est écrit une fois et ensuite on l'apelle au besoin. Concrètement cela se traduit par :


  1. import std.stdio;
  2. import std.string;
  3.  
  4. size_t addition( size_t a, size_t b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. size_t chiffre1 = 2;
  10. size_t chiffre2 = 3;
  11. size_t resultat = addition( chiffre1, chiffre2);
  12. write( "2 + 3 = " );
  13. write( resultat );
  14. }

Ici on a définit une fonction qui sappelle addition. Elle prends deux paramètres qui seront stocké respectivement dans a et b. Ces paramètres doivent êtres des entiers positifs car ils sont typé size_t. Enfin la fontion retourne une valeur de type size_t car avant le nom de la fonction il est écrit size_t.

Surcharger une fonctions

C'est bien jolie la fonction addition! Mais moi, je voudrais additionner des types différents! C'est simple il suffit d'écrire les fonctions avec les types désirés.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. size_t addition( size_t a, size_t b){
  5. return a + b ;
  6. }
  7.  
  8. float addition( size_t a, float b){
  9. return a + b ;
  10. }
  11.  
  12. double addition( double a, size_t b){
  13. return a + b ;
  14. }
  15.  
  16. double addition( double a, double b){
  17. return a + b ;
  18. }
  19.  
  20. void main( string[] args ){
  21. float chiffre1 = 2.6;
  22. size_t chiffre2 = 3;
  23. double chiffre3 = 5;
  24. float resultat1 = addition( chiffre2, chiffre1);
  25. size_t resultat2 = addition( chiffre2, chiffre2);
  26. double resultat3 = addition( chiffre3, chiffre2);
  27. double resultat4 = addition( chiffre3, chiffre3);
  28. witefln( "resultat1: %f | resultat2: %d | resultat3: %f | resultat4: %f ", resultat1, resultat2, resultat3, resultat4 );
  29. }

Le compilateur choisira la fonction addition correspondant aux types soumis. Le nom de la fonction suivie de ces paramètres forme la signature de la fonction. Le type de retour n'est pas compris dans la signature. Noter le f dans writefln f = format %d place un chiffre entier %f place un flottant. Les specifieurs: %d, %f sont les mêmes quen c++:

Les templates

Les fonctions ne permettent pas d'écrire en une fois "une addition c'est comme ça quelque soit le type"! est là qu'intervient les templates pour écrire des fonctions génériques.


  1. import std.stdio;
  2. import std.string;
  3.  
  4. T addition(T,U)( T a, U b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. float chiffre1 = 2.6;
  10. size_t chiffre2 = 3;
  11. float resultat = addition( chiffre1, chiffre2);
  12. write( "2.6 + 3 = " );
  13. write( resultat );
  14. }

Dans notre Exemple le template retournera toujours le même type que le type du prmier paramètre. Ainsi si on inverse l'ordre des paramètres chiffre1 et chiffre2 , le résultat sera de type size_t et donc tronqué (pas de chiffre après la virgule)

Un moyen simple de résoudre ce soucis et de simplement laisser le compilateur de déterminer automatiquement le type de retour. soit simplement:


  1. import std.stdio;
  2. import std.string;
  3.  
  4. auto addition(T,U)( T a, U b){
  5. return a + b ;
  6. }
  7.  
  8. void main( string[] args ){
  9. float chiffre1 = 2.6;
  10. size_t chiffre2 = 3;
  11. float resultat = addition( chiffre1, chiffre2);
  12. write( "2.6 + 3 = " );
  13. write( resultat );
  14. }

La seule modification est l'utilisation du mot clé auto.

Les commentaires

Afin de documenter ton code est pouvoir le comprendre facilement on peut ajouter des commentaires dans le code qui ne seront pas évalué par le compilateur. Un exemple vaut mieux qu'un long discours.


  1. // je suis un commentaire sur une ligne
  2. /*
  3.  je suis un commentaire
  4.  sur plusieurs ligne
  5.  */

Les tableaux

Lorsque l'on développe des applications on utilisent souvent les tableaux. Un tableau va permettre de stocker une suite d'information.


  1. int[] tableau = [1, 2, 3];

On a définit une variable tableau de type int, les signifie que c'est un tableau d'int. Pour accéder au premier élément on commence à compter à partir de 0.


  1. int[] tableau = [1, 2, 3];
  2. writeln( tableau[0] );

Slicing

On peut également récupérer une portion du tableau, par exemple on souhaite récupérer les élément à partir de l'indice 2 jusquà la fin:


  1. int[] tableau1 = [1, 2, 3];
  2. int[] tableau2 = tableau1[ 2 .. $];
  3. writeln( tableau2 );

Le symbole $ indique la fin du tableau, si l'on veut l'avant dernier élément on peut faire $ - 1 et ainsi des suite. La longueur d'un tableau peut être connu de cette façon.

Longueur de tableau


  1. int[] tableau1 = [1, 2, 3];
  2. writeln( tableau1.length );

On peut changer la taille d'un tableau:


  1. int[] tableau1 = [1, 2, 3];
  2. tableau1.length = tableau1.length + 5;
  3. tableau1[2 .. $] = [ 4, 5, 6, 7, 8 ];

Concatenation

Pour joindre deux tableaux on utilise le caractère ~


  1. int[] tableau1 = [1, 2, 3];
  2. tableau1 ~= [ 4, 5, 6, 7, 8 ];

Les boucles

Tant que (while)


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint i = 0;
  5. while (i < 10){
  6. writeln(i);
  7. i++;
  8. }
  9. }

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

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.


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint i = 10;
  5. do{
  6. writeln(i);
  7. i++;
  8. }
  9. while(i < 10);
  10. }

Pour (for)

On peut effectuer la déclaration d'une variabl (uint i = 0;)e, définir les conditions de la boucle ( i < 10) et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable, comme ici: ++i) ,dans la déclaration de la boucle for :


  1. for (uint i = 0; i < 10; ++i){
  2. writeln(i);
  3. }

Pour chaque (foreach)


  1. uint[5] a = [1,5,4,6,8];
  2. foreach(element;a){
  3. writeln(element);
  4. }

Pour chaque élément de a, on imprime sa valeur 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.


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

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 :


  1. import std.stdio;
  2.  
  3. void main(){
  4. uint i = 0;
  5. writeln("Bonjour");
  6. monEtiquette:
  7. i++;
  8. writefln("Valeur de i %d", i);
  9. if ( i < 2 ){
  10. goto monEtiquette;
  11. }
  12. writeln("Fin");
  13. }

Les chaines de caractères

Afin d'utiliser les chaines de( caractères, vous devez utiliser le module std.string. Une chaine de caractère commence et se termine par le symbole ", alors qu'un caractère commence et se termine par le symbole '. Soit:


  1. import std.string;
  2.  
  3. string maChaine = "je suis une chaine de caractère supportant l'unicode sans rien faire.";
  4. char caractere = 'c';

Les variables de type string sont immutables cela signigifie que le prochain chapitre, le lire, tu devras (yoda).

Les constantes

Le langage D différentie deux types de constante, const et immutable. const est utilisé pour dire que l'adresse de la variable x ne changera pas. immutable est utilisé pour dire que la valeur de la variable ne changera pas.

le mot clé const renvoie à la notion de pointeur et de référence. l'utilisation des pointeurs en D et pour moi est utile uniquement dans un but de faire une interface d'une application C.

Un peu de code:


  1. immutable int pi = 3.14; // la variable pi ne peut changer de valeur
  2. immutable int[] tableaux = [ 1, 2, 3 ]; // on ne peut pas modifier le contenu du tableau
  3. immutable int[1] tableaux = 4; // erreur on ne peut pas changer la valeur du tableau
  4. immutable int[] tableaux = [ 1, 4, 3]; // mais on peut donner une nouvelle référence

Le type string est immutable par conséquent on ne peut pas faire ça:


  1. string chaine = "Le langage C c'est cool";
  2. chaine[11] = 'D'; // -> Error: chaine[11] isn't mutable

pour cela on fait comme ça:


  1. string chaine = "Le langage C c'est cool";
  2. chaine = chaine[0 .. 11] ~ 'C' ~ chaine[12 .. $];

La différence ici est que l'on change la référence assigner à la variable chaine. Dans un premier temps on construit le tableau de caractère "Le langage D c'est cool" et la référence de ce tableau est assigné à la variable chaine.

Que peut on développer rapidement en langage D?

Jonathan Mercier

Bonjour cher lecteur,

En deux semaines avec des amis nous avons codé une petite application en D utilisant gtkD et derelict

On utilise un système multiagent (SMA) pour l'histoire. Une application dans le domaine biologique mais elle n'est pas la prétention d'être utilisable dans les laboratoires de recherche. C'est juste pour s'amuser et poser un cadre de développement.

Voici le résultat:

Nucleod

image réalisé par Nisaea

Que peut on développer rapidement en langage D?

Jonathan Mercier

Bonjour cher lecteur,

En deux semaines avec des amis nous avons codé une petite application en D utilisant gtkD et derelict

On utilise un système multiagent (SMA) pour l'histoire. Une application dans le domaine biologique mais elle n'est pas la prétention d'être utilisable dans les laboratoires de recherche. C'est juste pour s'amuser et poser un cadre de développement.

Voici le résultat:

Nucleod

image réalisé par Nisaea

What you can do in D programming quickly?

Jonathan Mercier

Dear reader,

In two weeks, me and some friends have wrote a litlle aplication using gtkD and derelict for openGL.

A little application with a multi-agent system (MAS) for biological process for fun not usable for biologist.

Nucleod

image make by Nisaea

see the result:

Cheers

Signed: bioinfornatics, Jonathan MERCIER

What you can do in D programming quickly?

Jonathan Mercier

Dear reader,

In two weeks, me and some friends have wrote a litlle aplication using gtkD and derelict for openGL.

A little application with a multi-agent system (MAS) for biological process for fun not usable for biologist.

Nucleod

image make by Nisaea

see the result:

Cheers

Signed: bioinfornatics, Jonathan MERCIER

Gtkd and D progamming

Jonathan Mercier

Dear reader, A new package come in to D repo for do a GUI with GTK named gtkd :)" class="smiley

How to install

very easy

$ su -c "yum install gtkd-devel gtkd-static"

How link my program with gtkd

For link your program you need use these ldc flag

-L-ldl -L-lgtkd

Gtkd example code

Content of main.d

module main;
 
import gtk.Main;
import gtk.MainWindow;
 
int main(char[][] args){
    Main.init(args); //initialize gtk
    MainWindow win = new MainWindow("D programming");
    //Creates a Window. The parameter is the title of our Window
    win.showAll(); //Show the Window
    Main.run(); //Run gtk (otherwise theres nothing to see)
    return 1;
}

Build

$ ldc -L-ldl -L-lgtkd  main.d

Run

$ ./main

Official web site

some example on official web site

Gtkd and D progamming

Jonathan Mercier

Dear reader, A new package come in to D repo for do a GUI with GTK named gtkd :)" class="smiley

How to install

very easy

$ su -c "yum install gtkd-devel gtkd-static"

How link my program with gtkd

For link your program you need use these ldc flag

-L-ldl -L-lgtkd

Gtkd example code

Content of main.d

module main;
 
import gtk.Main;
import gtk.MainWindow;
 
int main(char[][] args){
    Main.init(args); //initialize gtk
    MainWindow win = new MainWindow("D programming");
    //Creates a Window. The parameter is the title of our Window
    win.showAll(); //Show the Window
    Main.run(); //Run gtk (otherwise theres nothing to see)
    return 1;
}

Build

$ ldc -L-ldl -L-lgtkd  main.d

Run

$ ./main

Official web site

some example on official web site

D Programming and GTK

Jonathan Mercier

D Programming and GTK

Now gtkd is in D repo When i will have some time i will post post some example

D Programming and GTK

Jonathan Mercier

D Programming and GTK

Now gtkd is in D repo When i will have some time i will post post some example

D programming OpenGL and MVC Pattern

Jonathan Mercier

Dear,

Today we will see how to create a 3D application in D programming using the MVC Pattern. My code is not perfect, if you have suggestions feel free to propose them. :)" class="smiley

What you need

  • a D compiler like LDC
  • Tango library
  • Derelict library for use openGL

Architecture tree

src/
|-- mvc
|   |-- controller
|   |   `-- Controller.d
|   |-- event
|   |   `-- EventListener.d
|   |-- model
|   |   `-- Molecule.d
|   |-- observed
|   |   |-- Observable.d
|   |   |-- Observer.d
|   |   `-- Strategy.d
|   |-- mvc.d
|   `-- view
|       |-- View.d
|       `-- Window.d

Each directory is a package and each D file (*.d) a module.

  • Controller.d module is used to check events and datas.
  • EventListener.d module contains the structure to store events.
  • Molecule.d is a model of how it should be displayed.
  • Observed.d package contains some modules to implement some patterns.
  • View package contains some modules to display datas.
  • mvc.d is the main file.

Code Source

mvc.d

module mvc.mvc;
 
private import mvc.model.Molecule;
private import mvc.view.Window;
private import mvc.controller.Controller;
 
void main(char[][] args){
    Molecule    model       = new Molecule(10000,10);
    Window      window      = new Window(800, 600, "mvc", model);
}

The order in which you write your code is very important. At first, you need to create your model and to give a reference to the controller constructor. Then, you have to create an instance of your view with some parameters as a reference of controller. At last, you give a reference of this view to the controller and you run your application here with window.create().

Observer.d

module mvc.observed.Observer;
 
public interface Observer{
    public void update();
}

Observable.d

module mvc.observed.Observer;
 
public interface Observer{
    public void update(float[][] coordinates);
    public void update(size_t index, float[] coordinate);
}

Strategy.d

module mvc.model.Strategy;
 
public interface Strategy{
    public float[][]    getCoordinates3D();
    public float[]      getCoordinate3D(size_t index);
    public void         setCoordinates3D(float[][] coordinates3D);
    public void         setCoordinate3D(size_t index, float[] axis);
}

View.d

module mvc.view.View;
 
private import mvc.controller.Controller;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
public import mvc.model.Molecule;
 
 
public abstract class View: Observer {
    // Width window
    protected uint          width;
    // Height window
    protected uint          height;
    // Window title
    protected char[]        title;
    // Controller
    protected Controller    controller;
    // Model
    protected Molecule      model;
 
    public this(uint width, uint height, char[] title, ref Molecule model){
        this.width      = width;
        this.height     = height;
        this.title      = title;
        this.model      = model;
        this.controller = new Controller(model, this);
    }
 
    abstract public void update();
}

The view takes window size and a reference to the controller instance.

Window.d

module mvc.view.Window;
 
private import derelict.sdl.sdl;
private import derelict.sdl.sdltypes;
private import derelict.opengl.gl;
private import derelict.opengl.glu;
private import derelict.util.compat;
 
private import tango.stdc.stringz;
private import tango.math.Math;
import tango.io.Stdout;
 
private import mvc.view.View;
private import mvc.controller.Controller;
 
public class Window : View{
    private static uint nbArray = 0;
    private float           alpha;
    // Window
    private SDL_Surface     *screen;
    // Number of bits per pixel used for display. 24 => true color
    private uint            bitsPerPixel;
    // Field of view => the angle our camera will see vertically
    private float           fov;
    // Distance of the near clipping plane
    private float           nearPlane;
    // Distance of the far clipping plane
    private float           farPlane;
    // Event
    private SDL_Event       event;
    // Pixel on
    private float[][]      coordinates3D;
 
    public this(uint width, uint height, char[] title,ref Molecule model){
        super(width, height, title, model);
        this.screen         = null;
        this.bitsPerPixel   = 24;
        this.alpha          = 0.0f;
        this.fov            = 45.0f;
        this.nearPlane      = 0.1f;
        this.farPlane       = 100.0f;
        this.coordinates3D  = model.getCoordinates3D();
        Window.nbArray++;
        // Initialize SDL Derelict modules
        DerelictSDL.load();
        // Initialize GL Derelict modules
        DerelictGL.load();
        // Initialize GLU Derelict modules
        DerelictGLU.load();
        // Initialize SDL's VIDEO module
        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
        // Set buffer size
        SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 16);
        // Set depth size
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
        // Set stencil sizse
        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
        // Enable double-buffering
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        // Create our OpenGL window
        SDL_SetVideoMode(height, width, bitsPerPixel, SDL_OPENGL);
        // Set window title
        SDL_WM_SetCaption(toStringz(title), null);
        // switch to the projection mode matrix
        glMatrixMode(GL_PROJECTION);
        // load the identity matrix for projection
        glLoadIdentity();
        // Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height)
        float aspect = cast(GLfloat)height / cast(GLfloat)width;
        // Setup a perspective projection matrix
        gluPerspective(fov, aspect, nearPlane, farPlane);
        // Switch back to the modelview transformation matrix
        glMatrixMode(GL_MODELVIEW);
        // Load the identity matrix for modelview
        glLoadIdentity();
        // Create the window
        create();
    }
 
    public ~this(){
        cleanup();
    }
 
    public void refresh(){
        SDL_Flip(screen);
    }
 
    private void create(){
        SDL_Event   event;
        bool        isRunning   = true;
 
        this.screen = SDL_SetVideoMode(width, height, 0, SDL_OPENGL);
        if(this.screen == null)
            throw new Exception("Failed to set video mode: " ~ toDString(SDL_GetError()));
 
        glClearColor(0.0f,0.0f,0.0f,1.0f);
        glClearDepth(1.0f);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glLineWidth(0);
        controller.initModel();
 
        while(isRunning){
            SDL_PollEvent(&event);
            switch(event.type){
                case SDL_MOUSEMOTION:
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    break;
                // user has clicked on the window's close button
                case SDL_QUIT:
                    isRunning = controller.quit(event.type);
                    break;
                // by default, we do nothing => break from the switch
                default:
                    display();
                    break;
            }
        }
    }
 
    private void cleanup(){
        // tell SDL to quit
        if(SDL_Quit !is null)
            SDL_Quit();
        // release GL, GLU and SDL's shared libs
        DerelictGLU.unload();
        DerelictGL.unload();
        DerelictSDL.unload();
    }
 
    private void clear(){
        glClear(GL_COLOR_BUFFER_BIT);
    }
 
    private void display(){
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//definit couleur de fond
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glViewport(0,0,width,height);
        glPushMatrix();
        glTranslatef(0.0f, 0.0f, -40.0f);
        glRotatef(alpha,0.0f,1.0f,0.0f);
        glRotatef(30.0f,0.0f, 1.0f, 0.0f); //rotation 30 degre autour axe x
        glRotatef(45.0f,1.0f, 0.0f, 0.0f);
        draw();
        glPopMatrix();
        alpha = alpha + 0.1f;
        SDL_GL_SwapBuffers();//pour interchanger les buffers
  }
 
    public void draw(){
        if(coordinates3D != null && coordinates3D[0] != null){
            float[][] colorArray = createColors();
            glBegin (GL_LINE_STRIP);
            for(size_t color = 0; color < coordinates3D[0].length; color++){
                glColor3f(colorArray[0][color], colorArray[1][color], colorArray[2][color]);
                glVertex3f(coordinates3D[0][color],coordinates3D[1][color],coordinates3D[2][color]);
            }
            glEnd();
        }
    }
 
    public void update(){
        this.coordinates3D = model.getCoordinates3D();
        display();
    }
 
    private float[][] createColors(){
        float[][] colors = new float[][](3);
 
        // RGB are each on [0, 1]. S and V are returned on [0, 1] and H is
        // returned on [0, 6]. Exception: H is returned UNDEFINED if S==0.
        float r, g, b, h, s, v, m, n, f;
        int i;
        size_t index = 0;
        for (size_t k=0; k < coordinates3D[0].length; k++){
            //h = k * 360/ num;
            h = PI*2.0f/coordinates3D[0].length * k;
            s = 1.0f;
            v = 1.0f;
 
            i = cast(int)floor(h);
            f = h - i;
            if ( !(i&1) ) f = 1 - f; // if i is even
            m = v * (1 - s);
            n = v * (1 - s * f);
            switch (i) {
                case 6:
                case 0: r=v; g=n; b=m; break;
                case 1: r=n; g=v; b=m; break;
                case 2: r=m; g=v; b=n; break;
                case 3: r=m; g=n; b=v; break;
                case 4: r=n; g=m; b=v; break;
                case 5: r=v; g=m; b=n; break;
                default:break;
            }
 
            if(colors[0].length == index){
                colors[0].length = colors[0].length+50;
                colors[1].length = colors[1].length+50;
                colors[2].length = colors[2].length+50;
            }
            colors[0][index]=r; colors[1][index]=g; colors[2][index]=b;
            index++;
        }
        //resize
        colors[0].length = index;
        colors[1].length = index;
        colors[2].length = index;
        return colors;
    }
 
}

Window class inherits from View class. The constructor initializes an openGL/SDL application. There is a destructor for to quit properly an openGL application.
The create method is used to create a window and to handle user events. This method contains the main loop i.e while(isRunning) statement . Each turn of loop SDL give the last event with SDL_PollEvent(&event);. Each event is sent to controller.
Method createColors() converts a coordinate point to an openGL colour for fun. :)" class="smiley

Controller.d

module mvc.controller.Controller;
 
private import derelict.sdl.sdl;
private import mvc.model.Molecule;
private import mvc.event.EventListener;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
private import mvc.view.View;
 
public class Controller: Observer{
 
    private Molecule    model;
    private View        view;
    // Event handler
    private EventListener   eventListener;
 
    public this(ref Molecule model, ref View view){
        this.model  = model;
        this.view   = view;
        model.addObserver(this);
    }
 
    public void initModel(){
        model.create();
    }
 
    public bool quit(ubyte type){
        eventListener ~= (ubyte type)   {
                                            delete view;
                                        };
        eventListener(type);
        eventListener -= (ubyte type){};
        return false; // is running => no
    }
 
    public void update(){
        // do something
    }
}

We use a struct eventListener to handle events. At each turn, an event is added to eventListener i.e SDL_QUIT with symbol ~=. In fact, we add to the delegate several things to do. When you do eventListener(event.type); the function stored in the delegate for this event type will run. Here it is a little example but you can perform by addind a timer and handle a double click.

EventListener.d

module mvc.event.EventListener;
 
private import Array = tango.core.Array;
 
struct EventListener{
    alias void delegate(ubyte) delegateEvent;
    delegateEvent[] events;
 
    void opCall(ubyte event){
        foreach(eventInvocation; events)
            eventInvocation(event);
     }
 
    void opCatAssign( delegateEvent eventsInvocation ){
        events ~= eventsInvocation;
    }
 
    void opSubAssign( delegateEvent eventsInvocation ){
        Array.remove(events, eventsInvocation);
        events.length = events.length - 1;
    }
}

This structure is used to handle event. In D programming, to handle an event it is the same way as C#. You need to use a delegate, you can see to in some examples written in C# that the way is close. Here, we overload 3 operators:

  • () as opCall when you do eventListener(event.type); all things stored will run
  • ~= as opCatAssign you add several things to do in queue (delegate array)
  • -= as opSubAssign once time you have run all things to do for an event, you can remove these things from queue

Molecule.d

module mvc.model.Molecule;
 
private import tango.math.random.Random;
private import tango.math.Math;
private import Array    = tango.core.Array;
import tango.io.Stdout;
 
private import mvc.observed.Strategy;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
 
class Molecule : Strategy, Observable{
    private size_t      numberOfAtom;
    private size_t      radius;
    private float[][]   coordinates3D; //coordinates3D[0] -> x, coordinates3D[1] -> y, coordinates3D[2] -> z
    // Observer array;
    private Observer[]  observers;
 
    public this(size_t numberOfAtom, size_t radius){
        this.numberOfAtom           = numberOfAtom;
        this.radius                 = radius;
        this.coordinates3D          = new float[][](3);
        this.coordinates3D[0].length= numberOfAtom;
        this.coordinates3D[1].length= numberOfAtom;
        this.coordinates3D[2].length= numberOfAtom;
    };
 
    public void create(){
        size_t theta    = 0;
        size_t phi      = 0;
        size_t counter  = 0;
        while(counter < numberOfAtom){
            if(counter == 0){
                theta   = rand.uniformR(180);
                phi     = rand.uniformR(360);
            }
            else{
                theta   = rand.uniformR2( theta, theta+5 );
                phi     = rand.uniformR2( phi, phi+5 );
            }
            if(coordinates3D[0].length == counter){
                 coordinates3D[0].length = coordinates3D[0].length + 50;
                 coordinates3D[1].length = coordinates3D[1].length + 50;
                 coordinates3D[2].length = coordinates3D[2].length + 50;
            }
            // X
            coordinates3D[0][counter] = radius * sin(theta*PI/180) * cos(phi*PI/180);
            // Y
            coordinates3D[1][counter] = radius * sin(theta*PI/180) * sin(phi*PI/180);
            // Z
            coordinates3D[2][counter] = radius * cos(theta*PI/180);
            counter++;
        }
        // resize array
        coordinates3D[0].length = counter;
        coordinates3D[1].length = counter;
        coordinates3D[2].length = counter;
        notify();
    }
 
    /* *********************************************
     * Stragtegy
     */
 
    public float[][] getCoordinates3D(){
            return this.coordinates3D.dup;
    }
 
    public float[] getCoordinate3D(size_t index){
            return this.coordinates3D[index].dup; // Array of x,y,z
    }
 
    public void setCoordinates3D(float[][] coordinates3D){
            this.coordinates3D = coordinates3D;
            notify();
    }
 
    public void setCoordinate3D(size_t index, float[] axis){
            this.coordinates3D[index] = axis;
            notify();
    }
 
    /* *********************************************
     * Observable
     */
 
    public void addObserver(Observer observer){
        observers.length= observers.length + 1;
        observers[$-1]  = observer;
    }
 
    public void removeObserver(Observer observer){
        Array.remove(observers, observer);
        observers.length = observers.length - 1;
    }
 
    public void removeObserver(size_t index){
        Observer tmp[] = observers[index+1..$].dup;
        observers[index..$-1] = tmp;
        observers.length = observers.length - 1;
    }
 
    public void notify(){
        foreach(observer; observers)
            observer.update();
    }
}

This object it is a model and stores atom coordinate in space. You can add some observers each time controller accepts a change, controller notifies model and model updates the view, the view converts data to graphic.

Build

just do in your source directory:

$ ldc  -g -w -L -ldl -L -lDerelictGL -L -lDerelictGLU  -L -lDerelictSDL -L -lDerelictUtil $(find . -name "*.d")

The end

It is a big code for an how-to, several new things. You will need to read more than once to understand all; otherwise you are a chief :)" class="smiley . OpenGL syntax is the same as in C, I think that the most harder thing to understand i think it is the event handler system. You can take a look to C# code or all things about delegate/clojure. Delegate system it is the same thing as function pointer in C.

Thanks for all

signed: Bioinfornatics aka Jonathan MERCIER

D programming OpenGL and MVC Pattern

Jonathan Mercier

Dear,

Today we will see how to create a 3D application in D programming using the MVC Pattern. My code is not perfect, if you have suggestions feel free to propose them. :)" class="smiley

What you need

  • a D compiler like LDC
  • Tango library
  • Derelict library for use openGL

Architecture tree

src/
|-- mvc
|   |-- controller
|   |   `-- Controller.d
|   |-- event
|   |   `-- EventListener.d
|   |-- model
|   |   `-- Molecule.d
|   |-- observed
|   |   |-- Observable.d
|   |   |-- Observer.d
|   |   `-- Strategy.d
|   |-- mvc.d
|   `-- view
|       |-- View.d
|       `-- Window.d

Each directory is a package and each D file (*.d) a module.

  • Controller.d module is used to check events and datas.
  • EventListener.d module contains the structure to store events.
  • Molecule.d is a model of how it should be displayed.
  • Observed.d package contains some modules to implement some patterns.
  • View package contains some modules to display datas.
  • mvc.d is the main file.

Code Source

mvc.d

module mvc.mvc;
 
private import mvc.model.Molecule;
private import mvc.view.Window;
private import mvc.controller.Controller;
 
void main(char[][] args){
    Molecule    model       = new Molecule(10000,10);
    Window      window      = new Window(800, 600, "mvc", model);
}

The order in which you write your code is very important. At first, you need to create your model and to give a reference to the controller constructor. Then, you have to create an instance of your view with some parameters as a reference of controller. At last, you give a reference of this view to the controller and you run your application here with window.create().

Observer.d

module mvc.observed.Observer;
 
public interface Observer{
    public void update();
}

Observable.d

module mvc.observed.Observer;
 
public interface Observer{
    public void update(float[][] coordinates);
    public void update(size_t index, float[] coordinate);
}

Strategy.d

module mvc.model.Strategy;
 
public interface Strategy{
    public float[][]    getCoordinates3D();
    public float[]      getCoordinate3D(size_t index);
    public void         setCoordinates3D(float[][] coordinates3D);
    public void         setCoordinate3D(size_t index, float[] axis);
}

View.d

module mvc.view.View;
 
private import mvc.controller.Controller;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
public import mvc.model.Molecule;
 
 
public abstract class View: Observer {
    // Width window
    protected uint          width;
    // Height window
    protected uint          height;
    // Window title
    protected char[]        title;
    // Controller
    protected Controller    controller;
    // Model
    protected Molecule      model;
 
    public this(uint width, uint height, char[] title, ref Molecule model){
        this.width      = width;
        this.height     = height;
        this.title      = title;
        this.model      = model;
        this.controller = new Controller(model, this);
    }
 
    abstract public void update();
}

The view takes window size and a reference to the controller instance.

Window.d

module mvc.view.Window;
 
private import derelict.sdl.sdl;
private import derelict.sdl.sdltypes;
private import derelict.opengl.gl;
private import derelict.opengl.glu;
private import derelict.util.compat;
 
private import tango.stdc.stringz;
private import tango.math.Math;
import tango.io.Stdout;
 
private import mvc.view.View;
private import mvc.controller.Controller;
 
public class Window : View{
    private static uint nbArray = 0;
    private float           alpha;
    // Window
    private SDL_Surface     *screen;
    // Number of bits per pixel used for display. 24 => true color
    private uint            bitsPerPixel;
    // Field of view => the angle our camera will see vertically
    private float           fov;
    // Distance of the near clipping plane
    private float           nearPlane;
    // Distance of the far clipping plane
    private float           farPlane;
    // Event
    private SDL_Event       event;
    // Pixel on
    private float[][]      coordinates3D;
 
    public this(uint width, uint height, char[] title,ref Molecule model){
        super(width, height, title, model);
        this.screen         = null;
        this.bitsPerPixel   = 24;
        this.alpha          = 0.0f;
        this.fov            = 45.0f;
        this.nearPlane      = 0.1f;
        this.farPlane       = 100.0f;
        this.coordinates3D  = model.getCoordinates3D();
        Window.nbArray++;
        // Initialize SDL Derelict modules
        DerelictSDL.load();
        // Initialize GL Derelict modules
        DerelictGL.load();
        // Initialize GLU Derelict modules
        DerelictGLU.load();
        // Initialize SDL's VIDEO module
        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
        // Set buffer size
        SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 16);
        // Set depth size
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
        // Set stencil sizse
        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
        // Enable double-buffering
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        // Create our OpenGL window
        SDL_SetVideoMode(height, width, bitsPerPixel, SDL_OPENGL);
        // Set window title
        SDL_WM_SetCaption(toStringz(title), null);
        // switch to the projection mode matrix
        glMatrixMode(GL_PROJECTION);
        // load the identity matrix for projection
        glLoadIdentity();
        // Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height)
        float aspect = cast(GLfloat)height / cast(GLfloat)width;
        // Setup a perspective projection matrix
        gluPerspective(fov, aspect, nearPlane, farPlane);
        // Switch back to the modelview transformation matrix
        glMatrixMode(GL_MODELVIEW);
        // Load the identity matrix for modelview
        glLoadIdentity();
        // Create the window
        create();
    }
 
    public ~this(){
        cleanup();
    }
 
    public void refresh(){
        SDL_Flip(screen);
    }
 
    private void create(){
        SDL_Event   event;
        bool        isRunning   = true;
 
        this.screen = SDL_SetVideoMode(width, height, 0, SDL_OPENGL);
        if(this.screen == null)
            throw new Exception("Failed to set video mode: " ~ toDString(SDL_GetError()));
 
        glClearColor(0.0f,0.0f,0.0f,1.0f);
        glClearDepth(1.0f);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glLineWidth(0);
        controller.initModel();
 
        while(isRunning){
            SDL_PollEvent(&event);
            switch(event.type){
                case SDL_MOUSEMOTION:
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    break;
                // user has clicked on the window's close button
                case SDL_QUIT:
                    isRunning = controller.quit(event.type);
                    break;
                // by default, we do nothing => break from the switch
                default:
                    display();
                    break;
            }
        }
    }
 
    private void cleanup(){
        // tell SDL to quit
        if(SDL_Quit !is null)
            SDL_Quit();
        // release GL, GLU and SDL's shared libs
        DerelictGLU.unload();
        DerelictGL.unload();
        DerelictSDL.unload();
    }
 
    private void clear(){
        glClear(GL_COLOR_BUFFER_BIT);
    }
 
    private void display(){
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//definit couleur de fond
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glViewport(0,0,width,height);
        glPushMatrix();
        glTranslatef(0.0f, 0.0f, -40.0f);
        glRotatef(alpha,0.0f,1.0f,0.0f);
        glRotatef(30.0f,0.0f, 1.0f, 0.0f); //rotation 30 degre autour axe x
        glRotatef(45.0f,1.0f, 0.0f, 0.0f);
        draw();
        glPopMatrix();
        alpha = alpha + 0.1f;
        SDL_GL_SwapBuffers();//pour interchanger les buffers
  }
 
    public void draw(){
        if(coordinates3D != null && coordinates3D[0] != null){
            float[][] colorArray = createColors();
            glBegin (GL_LINE_STRIP);
            for(size_t color = 0; color < coordinates3D[0].length; color++){
                glColor3f(colorArray[0][color], colorArray[1][color], colorArray[2][color]);
                glVertex3f(coordinates3D[0][color],coordinates3D[1][color],coordinates3D[2][color]);
            }
            glEnd();
        }
    }
 
    public void update(){
        this.coordinates3D = model.getCoordinates3D();
        display();
    }
 
    private float[][] createColors(){
        float[][] colors = new float[][](3);
 
        // RGB are each on [0, 1]. S and V are returned on [0, 1] and H is
        // returned on [0, 6]. Exception: H is returned UNDEFINED if S==0.
        float r, g, b, h, s, v, m, n, f;
        int i;
        size_t index = 0;
        for (size_t k=0; k < coordinates3D[0].length; k++){
            //h = k * 360/ num;
            h = PI*2.0f/coordinates3D[0].length * k;
            s = 1.0f;
            v = 1.0f;
 
            i = cast(int)floor(h);
            f = h - i;
            if ( !(i&1) ) f = 1 - f; // if i is even
            m = v * (1 - s);
            n = v * (1 - s * f);
            switch (i) {
                case 6:
                case 0: r=v; g=n; b=m; break;
                case 1: r=n; g=v; b=m; break;
                case 2: r=m; g=v; b=n; break;
                case 3: r=m; g=n; b=v; break;
                case 4: r=n; g=m; b=v; break;
                case 5: r=v; g=m; b=n; break;
                default:break;
            }
 
            if(colors[0].length == index){
                colors[0].length = colors[0].length+50;
                colors[1].length = colors[1].length+50;
                colors[2].length = colors[2].length+50;
            }
            colors[0][index]=r; colors[1][index]=g; colors[2][index]=b;
            index++;
        }
        //resize
        colors[0].length = index;
        colors[1].length = index;
        colors[2].length = index;
        return colors;
    }
 
}

Window class inherits from View class. The constructor initializes an openGL/SDL application. There is a destructor for to quit properly an openGL application.
The create method is used to create a window and to handle user events. This method contains the main loop i.e while(isRunning) statement . Each turn of loop SDL give the last event with SDL_PollEvent(&event);. Each event is sent to controller.
Method createColors() converts a coordinate point to an openGL colour for fun. :)" class="smiley

Controller.d

module mvc.controller.Controller;
 
private import derelict.sdl.sdl;
private import mvc.model.Molecule;
private import mvc.event.EventListener;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
private import mvc.view.View;
 
public class Controller: Observer{
 
    private Molecule    model;
    private View        view;
    // Event handler
    private EventListener   eventListener;
 
    public this(ref Molecule model, ref View view){
        this.model  = model;
        this.view   = view;
        model.addObserver(this);
    }
 
    public void initModel(){
        model.create();
    }
 
    public bool quit(ubyte type){
        eventListener ~= (ubyte type)   {
                                            delete view;
                                        };
        eventListener(type);
        eventListener -= (ubyte type){};
        return false; // is running => no
    }
 
    public void update(){
        // do something
    }
}

We use a struct eventListener to handle events. At each turn, an event is added to eventListener i.e SDL_QUIT with symbol ~=. In fact, we add to the delegate several things to do. When you do eventListener(event.type); the function stored in the delegate for this event type will run. Here it is a little example but you can perform by addind a timer and handle a double click.

EventListener.d

module mvc.event.EventListener;
 
private import Array = tango.core.Array;
 
struct EventListener{
    alias void delegate(ubyte) delegateEvent;
    delegateEvent[] events;
 
    void opCall(ubyte event){
        foreach(eventInvocation; events)
            eventInvocation(event);
     }
 
    void opCatAssign( delegateEvent eventsInvocation ){
        events ~= eventsInvocation;
    }
 
    void opSubAssign( delegateEvent eventsInvocation ){
        Array.remove(events, eventsInvocation);
        events.length = events.length - 1;
    }
}

This structure is used to handle event. In D programming, to handle an event it is the same way as C#. You need to use a delegate, you can see to in some examples written in C# that the way is close. Here, we overload 3 operators:

  • () as opCall when you do eventListener(event.type); all things stored will run
  • ~= as opCatAssign you add several things to do in queue (delegate array)
  • -= as opSubAssign once time you have run all things to do for an event, you can remove these things from queue

Molecule.d

module mvc.model.Molecule;
 
private import tango.math.random.Random;
private import tango.math.Math;
private import Array    = tango.core.Array;
import tango.io.Stdout;
 
private import mvc.observed.Strategy;
private import mvc.observed.Observer;
private import mvc.observed.Observable;
 
class Molecule : Strategy, Observable{
    private size_t      numberOfAtom;
    private size_t      radius;
    private float[][]   coordinates3D; //coordinates3D[0] -> x, coordinates3D[1] -> y, coordinates3D[2] -> z
    // Observer array;
    private Observer[]  observers;
 
    public this(size_t numberOfAtom, size_t radius){
        this.numberOfAtom           = numberOfAtom;
        this.radius                 = radius;
        this.coordinates3D          = new float[][](3);
        this.coordinates3D[0].length= numberOfAtom;
        this.coordinates3D[1].length= numberOfAtom;
        this.coordinates3D[2].length= numberOfAtom;
    };
 
    public void create(){
        size_t theta    = 0;
        size_t phi      = 0;
        size_t counter  = 0;
        while(counter < numberOfAtom){
            if(counter == 0){
                theta   = rand.uniformR(180);
                phi     = rand.uniformR(360);
            }
            else{
                theta   = rand.uniformR2( theta, theta+5 );
                phi     = rand.uniformR2( phi, phi+5 );
            }
            if(coordinates3D[0].length == counter){
                 coordinates3D[0].length = coordinates3D[0].length + 50;
                 coordinates3D[1].length = coordinates3D[1].length + 50;
                 coordinates3D[2].length = coordinates3D[2].length + 50;
            }
            // X
            coordinates3D[0][counter] = radius * sin(theta*PI/180) * cos(phi*PI/180);
            // Y
            coordinates3D[1][counter] = radius * sin(theta*PI/180) * sin(phi*PI/180);
            // Z
            coordinates3D[2][counter] = radius * cos(theta*PI/180);
            counter++;
        }
        // resize array
        coordinates3D[0].length = counter;
        coordinates3D[1].length = counter;
        coordinates3D[2].length = counter;
        notify();
    }
 
    /* *********************************************
     * Stragtegy
     */
 
    public float[][] getCoordinates3D(){
            return this.coordinates3D.dup;
    }
 
    public float[] getCoordinate3D(size_t index){
            return this.coordinates3D[index].dup; // Array of x,y,z
    }
 
    public void setCoordinates3D(float[][] coordinates3D){
            this.coordinates3D = coordinates3D;
            notify();
    }
 
    public void setCoordinate3D(size_t index, float[] axis){
            this.coordinates3D[index] = axis;
            notify();
    }
 
    /* *********************************************
     * Observable
     */
 
    public void addObserver(Observer observer){
        observers.length= observers.length + 1;
        observers[$-1]  = observer;
    }
 
    public void removeObserver(Observer observer){
        Array.remove(observers, observer);
        observers.length = observers.length - 1;
    }
 
    public void removeObserver(size_t index){
        Observer tmp[] = observers[index+1..$].dup;
        observers[index..$-1] = tmp;
        observers.length = observers.length - 1;
    }
 
    public void notify(){
        foreach(observer; observers)
            observer.update();
    }
}

This object it is a model and stores atom coordinate in space. You can add some observers each time controller accepts a change, controller notifies model and model updates the view, the view converts data to graphic.

Build

just do in your source directory:

$ ldc  -g -w -L -ldl -L -lDerelictGL -L -lDerelictGLU  -L -lDerelictSDL -L -lDerelictUtil $(find . -name "*.d")

The end

It is a big code for an how-to, several new things. You will need to read more than once to understand all; otherwise you are a chief :)" class="smiley . OpenGL syntax is the same as in C, I think that the most harder thing to understand i think it is the event handler system. You can take a look to C# code or all things about delegate/clojure. Delegate system it is the same thing as function pointer in C.

Thanks for all

signed: Bioinfornatics aka Jonathan MERCIER

About the proprietary D compiler DMD

Jonathan Mercier

Dear reader,

Since fedora 14 they are a free and open source compiler LDC. D programmer can use too Digital Mars D compiler DMD. In D world they are 2 D version D1 and D2. DMD compiler can compile only in 32 bits, but this the compiler the most used.

DMD version 1

Install DMD v1

you need install DMD v1 form this package:

$ wget http://ftp.digitalmars.com/dmd-1.065-0.i386.rpm
$ su -m -c 'yum localinstall --nogpgcheck dmd-1.065-0.i386.rpm'

Modify dmd.conf

with DMD v1 you can use Tango as standard runtime library, for this you need edit /etc/dmd.conf file as:

[Environment]

DFLAGS= -I/usr/include/d/tango -I/usr/include/d -I/usr/include/d/tango/core/vendor -L-L/usr/lib/libtango-dmd.a -version=Tango -defaultlib=tango-dmd -debuglib=tango-dmd

Install tango-dmd

Take package here:

$ wget http://bioinfornatics.fedorapeople.org/tango-dmd-devel-0.99.9-1.20101109svn5599.fc14.i686.rpm
$ su -m -c 'yum localinstall --nogpgcheck tango-dmd-devel-0.99.9-1.20101109svn5599.fc14.i686.rpm tango-devel'

DMD version 2

Install DMD v2

Take package here:

$ wget http://ftp.digitalmars.com/dmd-2.050-0.i386.rpm
$ su -m -c 'yum localinstall --nogpgcheck dmd-2.050-0.i386.rpm'

Modify dmd.conf

With D2 you can not use Tango for the moment (only in D1) so you need use Phobos, for this edit /etc/dmd.conf as

[Environment]

DFLAGS= -I/usr/include/d/dmd/druntime/import/ -I/usr/include/d/dmd/phobos -I/usr/include/d -L-L/usr/lib/ -version=Phobos

Note

LDC developper and Tango developper works for port to D2 any help has appreciated

Tango

repository: git clone git://supraverse.net/tango.git

irc channel(freenode): #d.tango

LDC

repository: hg clone http://bitbucket.org/prokhin_alexey/ldc2

irc channel(freenode): #ldc

Thanks for all

signed: Bioinfornatics as Jonathan MERCIER

About the proprietary D compiler DMD

Jonathan Mercier

Dear reader,

Since fedora 14 they are a free and open source compiler LDC. D programmer can use too Digital Mars D compiler DMD. In D world they are 2 D version D1 and D2. DMD compiler can compile only in 32 bits, but this the compiler the most used.

DMD version 1

Install DMD v1

you need install DMD v1 form this package:

$ wget http://ftp.digitalmars.com/dmd-1.065-0.i386.rpm
$ su -m -c 'yum localinstall --nogpgcheck dmd-1.065-0.i386.rpm'

Modify dmd.conf

with DMD v1 you can use Tango as standard runtime library, for this you need edit /etc/dmd.conf file as:

[Environment]

DFLAGS= -I/usr/include/d/tango -I/usr/include/d -I/usr/include/d/tango/core/vendor -L-L/usr/lib/libtango-dmd.a -version=Tango -defaultlib=tango-dmd -debuglib=tango-dmd

Install tango-dmd

Take package here:

$ wget http://bioinfornatics.fedorapeople.org/tango-dmd-devel-0.99.9-1.20101109svn5599.fc14.i686.rpm
$ su -m -c 'yum localinstall --nogpgcheck tango-dmd-devel-0.99.9-1.20101109svn5599.fc14.i686.rpm tango-devel'

DMD version 2

Install DMD v2

Take package here:

$ wget http://ftp.digitalmars.com/dmd-2.050-0.i386.rpm
$ su -m -c 'yum localinstall --nogpgcheck dmd-2.050-0.i386.rpm'

Modify dmd.conf

With D2 you can not use Tango for the moment (only in D1) so you need use Phobos, for this edit /etc/dmd.conf as

[Environment]

DFLAGS= -I/usr/include/d/dmd/druntime/import/ -I/usr/include/d/dmd/phobos -I/usr/include/d -L-L/usr/lib/ -version=Phobos

Note

LDC developper and Tango developper works for port to D2 any help has appreciated

Tango

repository: git clone git://supraverse.net/tango.git

irc channel(freenode): #d.tango

LDC

repository: hg clone http://bitbucket.org/prokhin_alexey/ldc2

irc channel(freenode): #ldc

Thanks for all

signed: Bioinfornatics as Jonathan MERCIER

Making a web application as JEE in D Programming

Jonathan Mercier

Hello dear reader,
Today I present to you how to create a web application in D with Tango and Mango

Prerequisites

Repo for D programming

Add D repository as explained here: repo for D programming
Then install the mango-devel package

$ su -c 'yum install mango-devel'

FireWall

You need :

  • Open ports 8080 tcp and udp
  • Start httpd service
$ su -c 'service httpd start'

Software Architecture

.
|-- fr
|   `-- bioinfornatics
|       `-- bioinformatic
|           |-- controller
|           |   `-- Controller.d
|           |-- main.d
|           |-- model
|           `-- view
|               |-- Home.d
|               `-- Introduction.d

PFor this:

$ mkdir -p fr/bioinfornatics/bioinformatic/controller  fr/bioinfornatics/bioinformatic/viewfr/ bioinfornatics/bioinformatic/model

Code example

File main.d

module fr.bioinfornatics.bioinformatic.main;
private import tango.util.log.Log                                   : Log, Logger;
private import tango.net.InternetAddress                            : InternetAddress;
private import mango.net.servlet.ServletProvider                    : ServletProvider;
private import mango.net.servlet.ServletContext                     : ServletContext;
private import mango.net.http.server.HttpServer                     : HttpServer;
private import mango.net.servlet.tools.AdminServlet                 : AdminServlet;
private import fr.bioinfornatics.bioinformatic.controller.Controller: Controller;
 
void main(){
    Logger logger           = Log.lookup("fr.bioinfornatics.bioinformatic.main");
    // Construct a servlet-provider
    ServletProvider sp      = new ServletProvider(logger);
    logger.info ("registering servlets");
    // Create a log-admin servlet
    new AdminServlet (sp, sp.getDefaultContext);
    // Create a controller object for request uri web page
    Controller controller   = new Controller(logger);
    // Create a context for D_Programming servlets
    ServletContext context  = sp.addContext(new ServletContext (""));
    // Map all requests to our controller servlet
    sp.addMapping("/",                                          sp.addServlet (controller, context));
    sp.addMapping("/introduction",                              sp.addServlet (controller, context));
    sp.addMapping("/first_programm",                            sp.addServlet (controller, context));
    sp.addMapping("/basics_of_imperative_programming_language", sp.addServlet (controller, context));
    sp.addMapping("/object_oriented_programming",               sp.addServlet (controller, context));
    // Bind to port 80 on a local address
    InternetAddress addr    = new InternetAddress (8080);
    // Create a (1 thread) server using the ServiceProvider to service requests
    HttpServer server       = new HttpServer (sp, addr, 1, logger);
    // Start listening for requests (but this thread does not listen)
    logger.info("starting server");
    server.start;
}

Logger is a practical purpose to list the different events
We create an instance of class Controller, this item will receive different context that is defined later and redirect to the appropriate page
Then we create an instance of the ServletContext class that will handle the different context (web pages) requested.
It defines address and port for access to web site using an instance of InternetAddress,here port is set to 8080.
Then we built the server with an instance of class: ServletProvider, InternetAddress, Logger and we start it.

File Controller.d

module fr.bioinfornatics.bioinformatic.controller.Controller;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for logging
private import tango.util.log.Log                       : Logger;
// for get uri
private import tango.net.model.UriView                 : UriView;
private import fr.bioinfornatics.bioinformatic.view.Introduction;
private import fr.bioinfornatics.bioinformatic.view.Home;
 
public class Controller : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Controller");
        logger.info("Controller object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        switch(request.uri.getPath){
            case "/introduction":
                Introduction introduction = new Introduction(logger);
                introduction.service(request,response);
                break;
            case "/first_programm":
                break;
            case "/basics_of_imperative_programming_language":
                break;
            case "/object_oriented_programming":
                break;
            default:
                Home home = new Home(logger);
                home.service(request,response);
                break;
        }
 
    }
}

The Controller and the servlet application's main website, her work is to verify the user requests such as urls and input fields user forms and then redirect to the requested page.

File Home.d

module fr.bioinfornatics.bioinformatic.view.Home;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for write content web page
private import tango.io.model.IConduit                  : OutputBuffer;
private import mango.io.protocol.model.IWriter          : IWriter;
private import tango.util.log.Log                       : Logger;
 
class Home : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Home");
        logger.info("Home object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        logger.info ("Request for Home");
        // say we are writing html
        response.setContentType ("text/html");
        // get the response output ...
        OutputBuffer output = response.buffer;
        // write HTML preamble ...
        output  ("<HTML>\n\t<HEAD>\n\t\t<TITLE>Home Page</TITLE>\n\t</HEAD>\n\t<BODY>\n\t\t"c)
                ("<P>Hello</P>\n\t\t"c)
                ("<UL>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/introduction\">Introduction</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/first_program\">First program</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/basics_of_imperative_programming_language\">Basics of imperative programming language</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/object_oriented_programming\">Object oriented programming</a>\n\t\t\t"c)
                ("</UL>\n\t"c)
                ("</BODY>\n</HTML>"c);
    }
 
}

This class is used to generate the HTML for the main page where the service method is invoked.

File Introduction.d

module fr.bioinfornatics.bioinformatic.view.Introduction;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for write content web page
private import tango.io.model.IConduit                  : OutputBuffer;
private import tango.util.log.Log                       : Logger;
 
class Introduction : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Introduction");
        logger.info("Introduction object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        logger.info ("Request for Introduction");
        // say we are writing html
        response.setContentType ("text/html");
        // get the response output ...
        OutputBuffer output = response.buffer;
        // write HTML preamble ...
        output  ("<HTML>\n\t<HEAD>\n\t\t<TITLE>Introduction</TITLE>\n\t</HEAD>\n\t<BODY>\n\t")
                ("<P>D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. Special attention is given to the needs of quality assurance, documentation, management, portability and reliability. The D language is statically typed and compiles directly to machine code. It's multiparadigm, supporting many programming styles: imperative, object oriented, and metaprogramming. It's a member of the C syntax family, and its appearance is very similar to that of C++. Here's a quick list of <a href=\"http://www.digitalmars.com/d/2.0/comparison.html\">features</a>.</P>\n\t"c)
                ("<P>It is not governed by a corporate agenda or any overarching theory of programming. The needs and contributions of the <a href=\"http://www.digitalmars.com/NewsGroup.html\">D programming community</a> form the direction it goes.</P>\n"c)
                ("</BODY>\n</HTML>"c);
    }
 
}

This class is used to generate the HTML page introduction where the service method is invoked.

Compile and run the web application

$ cd /path/to/my/project
$ ldc  -w -L -lmango $(find -name "*.d") -of example

No compiles in recovering all the files whose extension is *.d with mango library, executable name will beexample.
Then run application

$ ./example

Now open your web browser and go to localhost

Faire une application web en D comme en JEE

Jonathan Mercier

Bonjour cher lecteur,
Aujourd'hui je vous présente comment créé une application web en D avec Tango et Mango

Prérequis

Dépôt D

Ajouter le dépôt D comme expliqué ici: Depôt pour le langage D
Installer ensuite le paquet mango-devel

$ su -c 'yum install mango-devel'

Pare-Feu

Vous devez :

  • ouvrir les ports 8080 tcp et udp
  • démarrer le service httpd
$ su -c 'service httpd start'

Architecture Logiciel

.
|-- fr
|   `-- bioinfornatics
|       `-- bioinformatic
|           |-- controller
|           |   `-- Controller.d
|           |-- main.d
|           |-- model
|           `-- view
|               |-- Home.d
|               `-- Introduction.d

Pour cela:

$ mkdir -p fr/bioinfornatics/bioinformatic/controller  fr/bioinfornatics/bioinformatic/viewfr/ bioinfornatics/bioinformatic/model

Exemple de code

Fichier main.d

module fr.bioinfornatics.bioinformatic.main;
private import tango.util.log.Log                                   : Log, Logger;
private import tango.net.InternetAddress                            : InternetAddress;
private import mango.net.servlet.ServletProvider                    : ServletProvider;
private import mango.net.servlet.ServletContext                     : ServletContext;
private import mango.net.http.server.HttpServer                     : HttpServer;
private import mango.net.servlet.tools.AdminServlet                 : AdminServlet;
private import fr.bioinfornatics.bioinformatic.controller.Controller: Controller;
 
void main(){
    Logger logger           = Log.lookup("fr.bioinfornatics.bioinformatic.main");
    // Construct a servlet-provider
    ServletProvider sp      = new ServletProvider(logger);
    logger.info ("registering servlets");
    // Create a log-admin servlet
    new AdminServlet (sp, sp.getDefaultContext);
    // Create a controller object for request uri web page
    Controller controller   = new Controller(logger);
    // Create a context for D_Programming servlets
    ServletContext context  = sp.addContext(new ServletContext (""));
    // Map all requests to our controller servlet
    sp.addMapping("/",                                          sp.addServlet (controller, context));
    sp.addMapping("/introduction",                              sp.addServlet (controller, context));
    sp.addMapping("/first_programm",                            sp.addServlet (controller, context));
    sp.addMapping("/basics_of_imperative_programming_language", sp.addServlet (controller, context));
    sp.addMapping("/object_oriented_programming",               sp.addServlet (controller, context));
    // Bind to port 80 on a local address
    InternetAddress addr    = new InternetAddress (8080);
    // Create a (1 thread) server using the ServiceProvider to service requests
    HttpServer server       = new HttpServer (sp, addr, 1, logger);
    // Start listening for requests (but this thread does not listen)
    logger.info("starting server");
    server.start;
}

Logger est un objet pratique pour lister les différents évènements.
On créé une instance de la classe Controller, cet objet recevra les différents context que l'on défini après et redirigera vers la page approprié
Ensuite on crée une instance de la classe ServletContext qui gérera les différents context (pages web) existant.
On définit l'adresse et le port pour accéder au site à l'aide d'une instance de la classe InternetAddress ici on on définit le port 8080 pour accéder au site web
Ensuite on construit le serveur avec une instance des classes: ServletProvider, InternetAddress, Logger et on le démarre

Fichier Controller.d

module fr.bioinfornatics.bioinformatic.controller.Controller;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for logging
private import tango.util.log.Log                       : Logger;
// for get uri
private import tango.net.model.UriView                 : UriView;
private import fr.bioinfornatics.bioinformatic.view.Introduction;
private import fr.bioinfornatics.bioinformatic.view.Home;
 
public class Controller : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Controller");
        logger.info("Controller object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        switch(request.uri.getPath){
            case "/introduction":
                Introduction introduction = new Introduction(logger);
                introduction.service(request,response);
                break;
            case "/first_programm":
                break;
            case "/basics_of_imperative_programming_language":
                break;
            case "/object_oriented_programming":
                break;
            default:
                Home home = new Home(logger);
                home.service(request,response);
                break;
        }
 
    }
}

Le Controller et la servlet principale de l'application web, son travail sera de vérifier les demandes utilisateurs comme les urls entrée et les champs utilisateurs des formulaires puis de rediriger vers la page demandé.

Fichier Home.d

module fr.bioinfornatics.bioinformatic.view.Home;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for write content web page
private import tango.io.model.IConduit                  : OutputBuffer;
private import mango.io.protocol.model.IWriter          : IWriter;
private import tango.util.log.Log                       : Logger;
 
class Home : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Home");
        logger.info("Home object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        logger.info ("Request for Home");
        // say we are writing html
        response.setContentType ("text/html");
        // get the response output ...
        OutputBuffer output = response.buffer;
        // write HTML preamble ...
        output  ("<HTML>\n\t<HEAD>\n\t\t<TITLE>Home Page</TITLE>\n\t</HEAD>\n\t<BODY>\n\t\t"c)
                ("<P>Hello</P>\n\t\t"c)
                ("<UL>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/introduction\">Introduction</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/first_program\">First program</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/basics_of_imperative_programming_language\">Basics of imperative programming language</a>\n\t\t\t"c)
                ("<LI><a href=\"http://localhost:8080/object_oriented_programming\">Object oriented programming</a>\n\t\t\t"c)
                ("</UL>\n\t"c)
                ("</BODY>\n</HTML>"c);
    }
 
}

Cette classe permet de générer le code HTML de la page principale lorsque la méthode service est invoqué.

Fichier Introduction.d

module fr.bioinfornatics.bioinformatic.view.Introduction;
// for testing the servlet-engine
private import mango.net.servlet.Servlet                : Servlet;
private import mango.net.servlet.model.IServletRequest  : IServletRequest;
private import mango.net.servlet.model.IServletResponse : IServletResponse;
// for write content web page
private import tango.io.model.IConduit                  : OutputBuffer;
private import tango.util.log.Log                       : Logger;
 
class Introduction : Servlet{
    private Logger logger;
 
    public this(Logger log){
        logger = log;
        logger  = log.lookup("fr.bioinfornatics.bioinformatic.controller.Introduction");
        logger.info("Introduction object is constructed");
    }
 
    //Handle all the different request methods ...
    void service (IServletRequest request, IServletResponse response){
        logger.info ("Request for Introduction");
        // say we are writing html
        response.setContentType ("text/html");
        // get the response output ...
        OutputBuffer output = response.buffer;
        // write HTML preamble ...
        output  ("<HTML>\n\t<HEAD>\n\t\t<TITLE>Introduction</TITLE>\n\t</HEAD>\n\t<BODY>\n\t")
                ("<P>D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. Special attention is given to the needs of quality assurance, documentation, management, portability and reliability. The D language is statically typed and compiles directly to machine code. It's multiparadigm, supporting many programming styles: imperative, object oriented, and metaprogramming. It's a member of the C syntax family, and its appearance is very similar to that of C++. Here's a quick list of <a href=\"http://www.digitalmars.com/d/2.0/comparison.html\">features</a>.</P>\n\t"c)
                ("<P>It is not governed by a corporate agenda or any overarching theory of programming. The needs and contributions of the <a href=\"http://www.digitalmars.com/NewsGroup.html\">D programming community</a> form the direction it goes.</P>\n"c)
                ("</BODY>\n</HTML>"c);
    }
 
}

Cette classe permet de générer le code HTML de la page introduction lorsque la méthode service est invoqué.

Compiler et lancer l'application web

$ cd /path/to/my/project
$ ldc  -w -L -lmango $(find -name "*.d") -of example

On compile en récupérant tout les fichier dont l'extention est *.d contre la bibliothèque mango le nom de l'éxécutable sera example
Ensuite on lance l'application

$ ./example

Maintenant ouvrez votre navigateur web et allez sur localhost

A bientôt

Signé: bioinfornatics, Jonathan MERCIER

D Programming with SDL and openGL

Jonathan Mercier

Hello dear reader,

Today I present to you how to make D program using 2D and 3D with SDL and OpenGL.

Prerequisites

Add the D repository as explained here: Repo for D-programming
Then install the packages Derelict-SDL and Derelict-GL, static libraries and development :

# yum install  derelict-SDL* derelict-GL*

Example

Create a file that contains main.d

private import Display;
private import derelict.sdl.sdl:    SDL_Event, SDL_PollEvent, SDL_QUIT;
 
void main(){
    bool    isRunning   = true;
    Display display     = new Display();
    scope(exit) display.cleanup();
    while(isRunning){
        isRunning = display.event();
        // clear the screen. by default it clears to black
        display.clear();
        //display graphic
        display.drawGLFrame();
    }
}
  1. We set a boolean to the main program loop
  2. We creates an instance of display class that we will its contents later
  3. When program will exit , it will execute mandatory display.cleanup ()
  4. So an event not give the order to leave (close button for example) a boolean will be true
    • It is refreshed image

Now create our file Display.d

private import derelict.sdl.sdl;
private import derelict.opengl.gl;
private import derelict.opengl.glu;
private import tango.stdc.stringz;
//private import tango.io.Stdout;
 
class Display{
    // horizontal and vertical screen resolution
    private uint height;
    private uint width;
    // number of bits per pixel used for display. 24 => true color
    private uint bitsPerPixel;
    // field of view => the angle our camera will see vertically
    private float fov;
    // distance of the near clipping plane
    private float nearPlane;
    // distance of the far clipping plane
    private float farPlane;
    /**
     * Setup some basic OpenGL parameters
     */
    private void setupGL(){
        // switch to the projection mode matrix
        glMatrixMode(GL_PROJECTION);
        // load the identity matrix for projection
        glLoadIdentity();
        // setup a perspective projection matrix
        gluPerspective(fov, cast(float)height / width, nearPlane, farPlane);
        // switch back to the modelview transformation matrix
        glMatrixMode(GL_MODELVIEW);
        // load the identity matrix for modelview
        glLoadIdentity();
    }
    /**
     * Library initializer
     */
    private void init(){
        // initialize SDL, GL and GLU Derelict modules
        DerelictSDL.load();
        DerelictGL.load();
        DerelictGLU.load();
        // initialize SDL's VIDEO module
        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
        // enable double-buffering
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        // create our OpenGL window
        SDL_SetVideoMode(height, width, bitsPerPixel, SDL_OPENGL);
        SDL_WM_SetCaption(toStringz("D is the best"), null);
        setupGL();
    }
    /**
     * Constructor
     */
    public this(){
        height      = 800;
        width       = 600;
        bitsPerPixel= 24;
        fov         = 90;
        nearPlane   = 0.1f;
        farPlane    = 100.f;
        init();
    }
    public ~this(){
        //cleanup();
    }
    /**
     * be nice and release all resources
     */
    public static void cleanup(){
        // tell SDL to quit
        if(SDL_Quit !is null)
            SDL_Quit();
        // release GL, GLU and SDL's shared libs
        DerelictGLU.unload();
        DerelictGL.unload();
        DerelictSDL.unload();
    }
    public void clear(){
        glClear(GL_COLOR_BUFFER_BIT);
    }
    public void drawGLFrame(){
        glBegin(GL_TRIANGLES);
            glColor3f (1,  0,  0);
            glVertex3f(-1, -1, -2);
            glColor3f (0,  1,  0);
            glVertex3f(1, -1, -2);
            glColor3f (0,  0,  1);
            glVertex3f(0,  1, -2);
        glEnd();
        // swap the buffers, making our backbuffer the visible one
        SDL_GL_SwapBuffers();
    }
 
    public bool event(){
        bool isRunning = true;
        SDL_Event event;
        // handle all SDL events that we might've received in this loop iteration
        while(SDL_PollEvent(&event)){
            switch(event.type){
                // user has clicked on the window's close button
                case SDL_QUIT:
                    isRunning = false;
                    break;
                // by default, we do nothing => break from the switch
                default:
                    break;
            }
            //Stdout.formatln("event.type: {}",event.type);
        }
        return isRunning;
    }
}

Here we create a class to manage the display quel'on called Display.

It contains attributes for:

  • The resolution of a window (height, width)
  • The quality of the image (BitsPerPixel)
  • Camera angle (fov)
  • Specifies the minimum distance between the viewer from the plane (nearPlane)
  • Specifies the maximum distance between the viewer from the plan (farPlane)

The default constructor initializes the attributes and the OpenGL library / SDL by calling the init() function
The event function returns a boolean, false if it wishes to leave if true
The function drawGLFrame draw triangle
The static function cleanup is optional it ensures proper to leave

I will let you work on the code :)" class="smiley

Compilation

To compile the application you must specify the libraries with which it is bound to be here:

$ ldc -g -w -L -ldl -L -lDerelictGL -L -lDerelictGLU  -L -lDerelictSDL -L -lDerelictUtil *.d -of example

Produce an executable named example

Execution

Just after compiling

$ ./example

Result

Capture-D_is_the_best.png

It's beautiful

Link

Cheers

Signed: bioinfornatics, Jonathan MERCIER

Programmer en D avec SDL et openGL

Jonathan Mercier

Bonjour cher lecteur,

Aujourd'hui je vous présente comment programmer en D pour faire des applications 2D et 3D grâce à SDL et openGL.

Prérequis

Ajouter le dépôt D comme expliqué ici: Depôt pour le langage D
Installer ensuite les paquets Derelict-SDL et Derelict-GL, les bibliothèques statiques et de développement soit

# yum install  derelict-SDL* derelict-GL*

Exemple de code

Créons un fichier main.d qui contient

private import Display;
private import derelict.sdl.sdl:    SDL_Event, SDL_PollEvent, SDL_QUIT;
 
void main(){
    bool    isRunning   = true;
    Display display     = new Display();
    scope(exit) display.cleanup();
    while(isRunning){
        isRunning = display.event();
        // clear the screen. by default it clears to black
        display.clear();
        //display graphic
        display.drawGLFrame();
    }
}
  1. On crée un booléen pour la boucle principale du programme
  2. On crée une instance de classe Display que l'on verra son contenu plus loin
  3. Lorsque le programme se terminera, il executera obligatoirement la méthode display.cleanup()
  4. Tant qu'un évènement donne pas l'ordre de quitter (bouton fermer par exemple) le booléen sera vrai
    • On on rafraichit l'image

Maintenant créons notre fichier Display.d

private import derelict.sdl.sdl;
private import derelict.opengl.gl;
private import derelict.opengl.glu;
private import tango.stdc.stringz;
//private import tango.io.Stdout;
 
class Display{
    // horizontal and vertical screen resolution
    private uint height;
    private uint width;
    // number of bits per pixel used for display. 24 => true color
    private uint bitsPerPixel;
    // field of view => the angle our camera will see vertically
    private float fov;
    // distance of the near clipping plane
    private float nearPlane;
    // distance of the far clipping plane
    private float farPlane;
    /**
     * Setup some basic OpenGL parameters
     */
    private void setupGL(){
        // switch to the projection mode matrix
        glMatrixMode(GL_PROJECTION);
        // load the identity matrix for projection
        glLoadIdentity();
        // setup a perspective projection matrix
        gluPerspective(fov, cast(float)height / width, nearPlane, farPlane);
        // switch back to the modelview transformation matrix
        glMatrixMode(GL_MODELVIEW);
        // load the identity matrix for modelview
        glLoadIdentity();
    }
    /**
     * Library initializer
     */
    private void init(){
        // initialize SDL, GL and GLU Derelict modules
        DerelictSDL.load();
        DerelictGL.load();
        DerelictGLU.load();
        // initialize SDL's VIDEO module
        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
        // enable double-buffering
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        // create our OpenGL window
        SDL_SetVideoMode(height, width, bitsPerPixel, SDL_OPENGL);
        SDL_WM_SetCaption(toStringz("D is the best"), null);
        setupGL();
    }
    /**
     * Constructor
     */
    public this(){
        height      = 800;
        width       = 600;
        bitsPerPixel= 24;
        fov         = 90;
        nearPlane   = 0.1f;
        farPlane    = 100.f;
        init();
    }
    public ~this(){
        //cleanup();
    }
    /**
     * be nice and release all resources
     */
    public static void cleanup(){
        // tell SDL to quit
        if(SDL_Quit !is null)
            SDL_Quit();
        // release GL, GLU and SDL's shared libs
        DerelictGLU.unload();
        DerelictGL.unload();
        DerelictSDL.unload();
    }
    public void clear(){
        glClear(GL_COLOR_BUFFER_BIT);
    }
    public void drawGLFrame(){
        glBegin(GL_TRIANGLES);
            glColor3f (1,  0,  0);
            glVertex3f(-1, -1, -2);
            glColor3f (0,  1,  0);
            glVertex3f(1, -1, -2);
            glColor3f (0,  0,  1);
            glVertex3f(0,  1, -2);
        glEnd();
        // swap the buffers, making our backbuffer the visible one
        SDL_GL_SwapBuffers();
    }
 
    public bool event(){
        bool isRunning = true;
        SDL_Event event;
        // handle all SDL events that we might've received in this loop iteration
        while(SDL_PollEvent(&event)){
            switch(event.type){
                // user has clicked on the window's close button
                case SDL_QUIT:
                    isRunning = false;
                    break;
                // by default, we do nothing => break from the switch
                default:
                    break;
            }
            //Stdout.formatln("event.type: {}",event.type);
        }
        return isRunning;
    }
}

Ici on crée une classe pour gérer l'affichage que l'on appelle Display.

Elle contient des attributs pour:

  • La résolution de la fenêtre (height, width)
  • La qualité de l'image (bitsPerPixel)
  • Angle de caméra (fov)
  • Spécifie la distance minimum entre le spectateur par rapport au plan (nearPlane)
  • Spécifie la distance maximum entre le spectateur par rapport au plan (farPlane)

Le constructeur par défaut initialise les attributs ainsi que les bibliothèques openGL/SDL par l'appel de la fonction init()
La fonction event renvoie un booléen, faux si on souhaite quitter sinon vrai
La fonction drawGLFrame dessine un triangle
La fonction statique cleanup est optionnelle elle permet de s'assurer de quitter proprement

Je vous laisse potasser sur le code :)" class="smiley

Compilation

Pour compiler l'application on doit spécifier les bibliothèques avec lesquelles le programme est lié soit ici:

$ ldc -g -w -L -ldl -L -lDerelictGL -L -lDerelictGLU  -L -lDerelictSDL -L -lDerelictUtil *.d -of example

Produira un éxécutable nommé example

Éxécution

Simplement, après compilation

$ ./example

Résultat

Capture-D_is_the_best.png

C'est beau hein!

Liens

A bientôt

Signé: bioinfornatics, Jonathan MERCIER