septembre
2008
Certains aspects de dodo sont quelque peu étranges ou bien archaïques, en ce qu’ils ont été décidés au tout début de la conception du langage puis sont restés. Ils donnent à dodo une saveur « hors norme » particulière.
1. Le point de référence
Ceci date même d’avant que le nom du langage soit décidé, il apparaît dans des esquisses de langage que j’avais faites avant de me lancer dans le projet de dodo.
Dans la plupart des langages de programmation, le passage de variables par référence est indiqué au niveau de la fonction. Par exemple en Pascal on peut écrire:
Procedure ValideDate(var Jour, Mois, An : word);
Le mot « var » indique que la variable est passée par référence. En son absence elle est passée par valeur.
Cependant quand on appelle cette fonction on n’indique pas à nouveau que l’on veut passer la variable par référence, on se contente de donner son nom. Remplacer le nom de variable par une valeur (par exemple: 1) donne une erreur, car la valeur ne peut pas être modifiée comme une variable.
L’idée du point de référence est de rendre explicite le fait qu’une variable est passée par référence au moment de l’appel. Pour reprendre l’exemple précédent en dodo:
method ValideDate: ValideDate(int .jour, .mois, .an). # Exemple d'utilisation int j = 3, m = 9, a = 2008 ValideDate(.j, .m, .a)
Une conséquence de ceci est que dans dodo, l’opération d’affectation et l’opération de comparaison peuvent utiliser le même signe « = » sans que cela lève d’ambiguïté. En effet la première requiert une référence alors que la seconde opère sur des valeurs.
# Comparer la valeur x avec la valeur 5 x = 5 # Assigner la valeur 5 à la variable x .x = 5
Une instruction qui n’a aucun effet (comme x = 5) génère un avertissement du compilateur, comme ça l’on sait qu’il manque un point.
2. Dérivation d’un prototype
Pour définir les attributs d’un objet dérivé d’un prototype, leur valeur est listée à côté du nom de l’attribut. En fait, cela date d’une vieille version de dodo où l’initialisation d’une variable se faisait sans signe « = ».
# Version moderne Area area = playground # Version obsolète (erreur de compilation) Area area playground;
J’ai fini par me rendre à l’évidence que cette notation n’est pas très lisible, et le signe égal a été réintroduit. Mais la notation est restée pour l’initialisation des attributs lors de la dérivation et pour les tableaux associatifs. Par exemple:
def maisonVerte = new maison(couleurMur vert, couleurToit gris)
3. Balises XML
On peut être surpris en voyant du code dodo dont la syntaxe semblerait plus à sa place dans le code d’une page web. En effet, dodo utilise le standard XML par endroits!
Cela remonte à une vieille idée, discutée à l’époque, de sauvegarder le programme comme un document XML. Avec à charge de l’éditeur de présenter le programme de façon lisible par le programmeur. Il y a plusieurs avantages à cela, mais ce n’est sûrement pas dans les projets immédiats (il faudrait déjà un éditeur capable de telles prouesses).
Bref, l’idée est venue de conserver certaines constructions dans leur forme originale en XML au lieu de définir une syntaxe dodo correspondante. C’est le cas des commentaires multilignes, des gestionnaires d’événement ou de tâche, et des états abstraits d’un objet.
Du point de vue esthétique les balises délimitent un bloc sans introduire un niveau de nesting supplémentaire. Par exemple:
int devineUnNombre(Enfant[] enfants) { return (map $$1 enfants.devine).average <catch event="ouille"> resume $$1 5 </catch> }
Si l’on éliminait XML on aurait:
int devineUnNombre(Enfant[] enfants) { return (map $$1 enfants.devine).average catch (ouille) { resume $$1 5 } }
Seule la version XML a été retenue. Attribuez ça au caractère particulier de dodo…
4. Liste de paramètres
Les paramètres d’une fonction peuvent être groupés par type. Ceci permet de ne spécifier le type qu’une fois au lieu de le répéter pour chaque paramètre. Les adeptes de la programmation fonctionnelle, habitués à l’inférence de type généralisée, en seront sûrement reconnaissant. Mais en voulant leur plaire dodo n’était pas très ami avec les habitudes des programmeurs C ou Java, en demandant de séparer les paramètres de type différent avec un point-virgule. Habituellement c’est une simple virgule.
Finalement il semble qu’utiliser une virgule ne pose pas de défi insurmontable au compilateur, donc c’est la dernière solution adoptée. En fin de compte le type d’un paramètre est optionnel s’il est le même que le paramètre précédent. Par exemple:
# Pour les adeptes du style fonctionnel def max(int a, b) = if (a < b) b else a # Pour les adeptes du style C int max(int a, int b) { return if (a < b) b else a; }
5. La flèche
La flèche de dodo « -> » apparaît à deux endroits différents, chacun lié à une notion importante pour le langage: la continuation. Une continuation est une suite d’instructions à exécuter par la suite. Par exemple quand une fonction termine, la continuation à exécuter est la suite d’instructions qui suit l’appel de fonction dans l’appelant.
Alors que je me battais pour comprendre la notion de continuation la notation à flèche m’est venue comme une façon facile de les représenter. Cela m’a encouragé à faire de la continuation un concept central de dodo. Exemple d’utilisation:
max(x, 15) -> xmax return(xmax)
Le code ci-dessus fournit la continuation commençant avec « -> » à la fonction max. Quand la fonction max termine, elle invoque la continuation avec sa valeur de retour. La continuation sauve cette valeur dans la variable xmax et appelle return(xmax).
La programmation basée sur les continuations n’est pas vraiment pratique, c’est pourquoi la flèche n’apparaît pas trop souvent dans un programme dodo. Mais en interne tout programme est transformé en notation fléchée.
6. Envoi de message
Le langage dodo impose une stricte séparation entre le programme principal et le code qui accède aux ressources du système, par exemple le réseau ou les fichiers. L’envoi de message est utilisé pour communiquer entre les deux mondes.
En vérité la syntaxe adoptée par dodo n’est pas très originale car elle est inspirée d’autres langages de programmation utilisant l’envoi de message, où le point d’exclamation indique que le message qui suit est envoyé à travers le « canal » qui le précède. Une originalité est que une « capacité » (droit de réaliser une opération) apparaît dans le message. Par exemple:
files!accesLectureScores.Open(fRead)
Cette instruction envoie à files
le message Open(fRead)
à l’aide de la capacité accesLectureScores
.
7. La balise UNDO
Pour la petite histoire ce qui suit est inspiré des scopes du langage D.
Le bloc « try » indique que les instructions contenues à l’intérieur peuvent donner lieu à des cas exceptionnels (condition d’erreur ou autre). Dans ce cas on peut faire suivre le bloc « try » d’instructions à exécuter dans tous les cas, exceptionnel ou non.
Donc il y a les instructions exécutées si tout se déroule normalement (dans le bloc « try »), les instructions à exécuter dans tous les cas… Il manque les instructions exécutées en cas d’exception. Pour cela on précède des instructions suivant le bloc « try » avec UNDO.
Il n’y a vraiment rien dans le langage qui ressemble à UNDO, dès lors je me réserve le droit de le changer dans le futur
Voilà, j’espère que cette petite rétrospective a aidé à lever le mystère sur certains aspects du langage dodo.
Site de dodo:
http://dodo.sourceforge.net
3. Je me suis maintenant débarrassé des balises XML restantes dans le langage, elles m’auraient en fait causé plus de problèmes qu’elle n’en vaillent si je décide de faire une forme XML de dodo.
Certaines ont été transformées en mots-clefs comme suggéré ci-dessus (catch, wrap, handler)
D’autres ont pris une forme avec soulignement (__Module__, __Library__, __State__)
7. La balise UNDO a maintenant pris une forme avec soulignement pour rester consistant: __Undo__
Tout ceci a bien changé…
Maintenant on a
2. Utiliser « : » pour séparer le nom de l’attribut de sa valeur
new maison(couleurMur: vert, couleurToit: gris)
5. La flèche n’a pas changé, mais en pratique la notation fléchée souffre du problème du « dangling else »:
e(x) -> j <br />
f(j) -> k <br />
g(k) <br />
| e <br />
t(e) <br />
À quelle flèche correspond l’alternative | e? Pour lever l’ambiguïté j’ai décidé que la notation fléchée doit se terminer avec un point-virgule (optionel avant une parenthèse fermante), ce qui donne:
e(x) -> j <br />
f(j) -> k <br />
g(k); # termine les continuations de f(j) <br />
| e <br />
t(e); <br />
7. Ce n’est pas encore sûr, mais il y a de bonnes chance qu’il faille une balise qui correspond aux instructions à exécuter en cas de succès. Peut-être la balise THEN…