Laurent proposait dans l’un de ses articles une critique d’une vingtaine de langages de programmation. Parmi ceux-ci, le Lua était présenté très brièvement. Je propose ici de développer un peu sur ce langage.
Il s’agit donc d’un langage particulièrement léger, qui s’intègre très facilement dans un projet, et qui bénéficie d’une documentation claire et d’une communauté relativement active.
Comme l’indique Laurent, le Lua est multi-paradigme. S’il se présente au premier abord comme un langage impératif, on peut également faire de l’objet (au prix de l’utilisation d’une bibliothèque) et il dispose de plus de tous les outils pour faire du fonctionnel (il me semble juste que l’on ne peut pas faire simplement de curryfication). Du point de vue de la syntaxe, c’est un langage très agréable qui permet d’exprimer les choses de façon très succincte. Ainsi on peut itérer sur un tableau avec un « foreach », on dispose de fonctions locales, il n’y a pas de point-virgule de fin de ligne, pas de parenthèses superflues…
Par contre c’est un langage qui souffre d’un très gros laxisme du point de vue du typage. Il est en effet typé (dynamiquement) dans le sens où l’on peut demander le type d’une variable, mais dans de nombreux cas si l’on utilise une variable d’un type au lieu d’un autre, elle est transtypée sans que cela pose de problème au langage. De plus on ne peut pas imposer le type attendu par une fonction, mais juste le vérifier à l’exécution. Enfin si l’on tente d’accéder à une variable qui n’existe pas, par exemple suite à une faute de frappe, cela ne gène pas le moins du monde le langage, qui renverra « nil » (valeur valide pour une variable). Naturellement c’est source de beaucoup d’erreurs, décelées seulement à l’exécution de la branche erronée.
Autres choix qui ne me plaisent pas : le fait que les variables soient globales sauf contre-indication explicite, et que les opérateurs logiques « or » et « and » qui, contrairement à ce que l’on pourrait attendre d’un langage moderne, ne renvoient pas un booléen mais l’opérande déterminante.
Du côté des outils fournis, le langage se veut doté d’un système de table très puissant, et s’il est vrai qu’il est pratique dans les cas simples, on en trouve très vite les limites. Par exemple on ne dispose pas de reverse-iterator, et en écrire un s’avère laborieux. De même, la fonction permettant de compter les éléments d’une table est en fait une sorte de hack qui ne fonctionne que pour les tables indexées, en renvoyant le plus grand indice consécutif. Si l’on veut une fonction sérieuse pour connaître cette information, on doit donc l’écrire. Le langage se veut également doté d’une gestion de chaînes puissantes. Pourtant la documentation explique que les expressions rationnelles ne sont pas POSIX pour des raisons de quantité de code nécessaire. Au final filtrer des motifs devient vite pénible dès que l’on sort des cas d’école, et l’ajout d’une nouvelle syntaxe maison vient perturber le principe de moindre surprise.
Enfin du point de vue des performances, le langage se place apparemment plutôt bien pour un langage interprété. Il est notamment possible de faire de la compilation just-in-time et d’atteindre ainsi des performances très correctes. Cela dit elles restent plombées apparemment par le typage dynamique. Un simple appel de fonction se révèle être déjà coûteux. Du point de vue de la gestion de la mémoire, il est assez difficile de savoir ce que l’interpréteur fait, mais il semblerait qu’il ne sache pas tirer parti du fait qu’une fonction est souvent appelée pour optimiser l’allocation de ses variables locales. À vérifier cela dit.
En conclusion c’est un langage très pratique, vivant, facilement intégrable, avec une syntaxe relativement agréable, mais qui souffre d’un trop grand manque de rigueur.