Dans la suite de mes trois précédents articles consacrés à ce sujet, j’ai commencé à écrire un très long article dans lequel je décortique point par point les différentes caractéristiques des langages de programmation. L’écriture de l’article m’a obligée à structurer mes idées, et m’a aidée à réaliser un certain nombre de choses. Par contre, l’article lui-même est devenu un long truc un peu indigeste, alors j’ai décidé de le mettre à la poubelle.
Pour le moment, je vais juste reprendre une partie de ce que j’avais écrit, concernant la syntaxe des langages.
Une des caractéristiques essentielles d’un langage de programmation, c’est d’être facile à lire et à relire. On doit pouvoir lire du code source comme un linguiste peut lire un texte écrit dans une langue étrangère.
Cela passe notamment par un syntaxe légère, qui ne se mette pas en travers de la lecture, qui ne soit pas inutilement verbeuse et qui reste sans ambiguïté.
Blocs, labels, accolades et indentation
Pour illustrer mon propos, je vais vous montrer comment on code la factorielle récursive dans plusieurs langages procéduraux. Tout d’abord en Pascal :
FUNCTION factorielle (n: shortint) : integer;
BEGIN
IF n <= 1 THEN
BEGIN
WRITELN('End of loop');
factorielle := 1
END
ELSE
BEGIN
WRITELN('Loop');
factorielle := n * factorielle (n - 1)
END;
END;
Ensuite en BASIC (VB.net, inspiré par le site Developpez.com, © Philippe Laserre) :
Function Factorielle (ByVal N as Long) As Long
If N=1 Then
Console.WriteLine("End of loop")
Return 1
End If
Console.WriteLine("Loop")
Return N * Factorielle(N - 1)
End Function
Et voici le code équivalent en C :
int factorielle(int n)
{
if (n <= 1)
{
printf("End of loop\n");
return 1;
}
printf("Loop\n");
return n * factorielle(n - 1);
}
Pour terminer cette démonstration, voici la même fonction factorielle en Python :
def factorielle(x):
if x <= 1:
print("End of loop\n")
return 1
print("Loop\n")
return x * factorielle(x - 1)
Je vous laisse voir le code équivalent en Ruby, qui conjugue syntaxe légères et typage dynamique comme le Python.
Je crois que j’ai déjà cité mon prof de C en prépa, qui parlait des différences entre les langages créés par des mathématiciens suisses (cf. le Pascal) et ceux créés par des hippies californiens (cf. le C). Et encore, l’exemple serait plus criant si il fallait déclarer des variables ; en Pascal c’est vraiment marrant.
Je vous rappelle que le BASIC est né en 1963, le Pascal en 1970, le C en 1972, le Python en 1990 et le Ruby en 1995. Il y a forcément une notion de modernisme dans la simplification de la syntaxe des langages.
Je ne parle pas de la compacité d’un code par rapport à l’autre, mais bien de sa lisibilité intrinsèque. Le C utilise des accolades, là où le Pascal et le BASIC utilisent du texte (BEGIN, END, End If, End Function). Savoir où placer les point-virgules en fin de ligne n’est pas forcément naturel au premier abord en Pascal, alors qu’en C le comportement est consistant ; le BASIC et le Python se suppriment quant à eux complètement cette contrainte. Pour finir, la déclaration de la fonction avec son type de retour et son paramètre, est assez similaire entre le Pascal et le BASIC ; le C est bien moins verbeux. En Python, il n’y a pas de déclaration du type des fonctions et des variables, c’est encore plus simple à lire (mais moins rigoureux diront certains).
Sur un exemple comme celui-ci, mon avis est assez évident. Le fait d’utiliser des termes textuels peut sembler plus facile à appréhender pour les débutants, mais j’y apporte deux objections : Premièrement, même si on ne vous explique pas le rôle des accolades, le code en C ci-dessus est très facilement compréhensible, et on devine sans peine à quoi elles servent. Deuxièmement, les éléments de syntaxe basique sont intégrés très rapidement par les codeurs débutants ; obliger les développeurs à affronter la pollution visuelle des BEGIN/END pendant tout le reste de leur vie me semble être un mauvais calcul.
Je ne veux pas tant montrer que je préfère la syntaxe du C que de pointer le genre de détails qui font qu’un langage peut − ou non − mettre des bâtons dans les roues des développeurs qui l’utilisent.
On peut remarquer que le Python va encore plus loin en supprimant même les accolades. C’est l’indentation qui détermine les blocs de code. Les experts du langage trouvent ça très positif : le code est plus simple car il ne nécessite plus aucune indication de début et fin de bloc, et cela unifie le formatage du code. Même si je suis sensible à ces arguments, j’y vois personnellement 3 inconvénients : le mélange d’espaces et de tabulations peut générer des bugs indémerdables, à plus forte raison quand plusieurs développeurs interviennent en utilisant des éditeurs de texte différents ; il n’y a rien pour “fermer” les blocs, on a l’impression que les fonctions flottent dans le vide (c’est une question d’habitude, je sais). Mais surtout, dans certains cas, on se retrouve à quand même utiliser des symboles de début et fin de bloc, et à ce moment-là l’indentation arrête d’être significative ; par exemple, quand on construit une liste, le code suivant est fonctionnel, complètement logique, mais brise l’indentation habituelle en Python :
ma_liste = [ "aaa", "bbb", "ccc" ]
Dollars et points-virgules
Les deux autres notions basiques sont l’utilisation du caractère dollar ($) devant les noms de variables et les points-virgules en fin d’expression.
Historiquement, le dollar était inutile dans les langages compilés (Pascal, C), mais traditionnel dans les langages de script (shell, Perl). C’est assez amusant, quand je code en C je me passe très bien des dollars, alors qu’en PHP je trouve ça naturel. C’est clairement une question d’habitude. J’ai tendance à trouver les dollars pratiques pour différencier d’un seul coup d’œil les variables des autres constructions du langage, comme les namespaces, ce qui peut s’avérer utile au fur et à mesure de l’ajout de fonctionnalités dans les langages modernes.
Les points-virgules en fin d’expression m’ont toujours semblés tout aussi naturels. Ils permettent de savoir où se termine l’expression. La plupart du temps il n’y en a pas besoin, car les expressions sont courtes et faciles à lire. Mais parfois − pas si rarement que ça, en fait − on écrit des expressions sur plusieurs lignes, et mon œil cherche instinctivement le point-virgule pour savoir où est la fin.
On peut remarquer que le Go (nouveau langage de Google) n’a pas besoin de point-virgule en fin de ligne ; mais, pour éviter les ambiguïtés, il impose que les accolades ouvrantes soient sur la même ligne que l’instruction if qui précède (cf. documentation). On en arrive donc à une situation très étrange, où pour simplifier l’écriture on se retrouve à la contraindre…
Un dernier point de détail concernant la syntaxe : L’utilisation des parenthèses.
Plusieurs langages n’obligent pas de mettre des parenthèses autour des paramètres d’une fonction. Moi, ça me gêne. Depuis le collège, on est habitué à écrire des fonctions mathématiques ; quand on écrit f(x), on ne se pose aucune question, on sait que f est une fonction et qu’elle prend un paramètre nommé x.
Parenthèses
Idem pour les parenthèses autour de la condition d’un if ou d’un while. Je trouve que ça donne une délimitation visuelle claire. Si on regarde l’exemple suivant (tiré de la documentation du Go) :
for i:= 0; i < flag.NArg(); i++ {
if i > 0 {
s+= space
}
s+= flag.Arg(i)
}
Je le trouve moins lisible que s’il s’écrivait :
for (i = 0; i < flag.NArg(); i++) {
if (i > 0)
s += space;
s += flag.Arg(i);
}
Mais c’est sûrement encore une question d’habitude.
Conclusion
Bon… Encore un article qui ne sert pas à grand-chose…
Tout ça pour dire que je suis habitué à un style de syntaxe auquel tout le monde est habitué, qui constitue les bases du C, du C++, du Perl, du Javascript, du PHP, …
J’ai un peu l’impression qu’après une période durant laquelle l’informatique s’est rapidement complexifiée avec l’arrivée des premiers gros ordinateurs, la syntaxe des langages a été simplifiée (merci Dennis Ritchie). Sur un cycle de re-complexification, on a abouti au C++, qui est quand même un monument à ce niveau. On a re-simplifié par la suite de différentes manières, plus ou moins réussies (Python, Lua, Java, Ruby, PHP, …).
Les être humains répétant régulièrement leurs erreurs, je pense que nous sommes actuellement dans un nouveau cycle de complexification. Il parait important d’ajouter des fonctionnalités aux langages, alors que ces mêmes fonctionnalités pourraient rester dans des bibliothèques externes ; il semble nécessaire de farcir les frameworks de capacités supplémentaires, alors que les systèmes de plugins qui sont là pour ça. On ajoute plein de choses dans les systèmes d’exploitation, pour finalement leur donner la simplicité des OS mobiles…



