Outils pour utilisateurs

Outils du site


lua

Différences

Cette page vous affiche les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue comparative

lua [2013/05/06 14:28] (Version actuelle)
Ligne 1: Ligne 1:
 +==== Problèmes de syntaxe ====
  
 +=== Opérateur ~= ===
 +
 +Lorsque tous les langages ou presque utilisent l'​opérateur **!=** ou **<>​** pour tester la non égalité, Lua impose l'​opérateur **~=**, qui est tout à fait inattendu, et donc contraire au principe de moindre surprise.
 +
 +=== Pas d'​opérateur ternaire ===
 +
 +Lua n'a pas d'​opérateur ternaire, mais la documentation officielle propose l'​utilisation des opérateurs **and** et **or** à la place. Le résultat est peu intuitif et une personne non habituée à ce type de contournement butera sur ce genre d'​utilisation.
 +<code lua>
 +foo = bar and baz or 42 -- En C cela s'​écrirait foo = bar ? baz : 42; sauf dans le cas bar == 0
 +</​code>​
 +
 +=== Pas de continue ===
 +
 +Le langage possède les mécanismes d'​interruption de code **break** et **return**, mais bizarrement **continue** est absent.
 +
 +=== Les tables ===
 +
 +Le langage se veut doté d’un système de table très puissant, mais bien qu'​effectivement pratique dans les cas simples, il est en réalité très limité. Les tables peuvent être indexées par des clés ou par des entiers. La bibliothèque standard propose une fonction permettant de compter les éléments d’une table, mais elle se contente de renvoyer le plus grand entier consécutif. Elle ne fonctionne donc pas dans le cas d'une table indexée par des clés, ou dans le cas où un élément est nil. Si l’on veut une fonction sérieuse pour connaître cette information,​ on doit donc l’écrire.
 +<code lua>
 +foo = 42
 +baz = "​baz"​
 +test = {foo, bar, baz} -- bar est nil
 +print(#​test) -- Affiche 3
 +test[5]="​test"​
 +print(#​test) -- Affiche 1
 +</​code>​
 +
 +Lua propose également un mécanisme d'​itérateur pour parcourir les éléments d'une table, avec les fonctions **pair** et **ipairs**, selon que les éléments sont indexés par clés ou par entiers. Mais rien n'est prévu pour pouvoir parcourir une liste à l'​envers. D'​ailleurs,​ le parcours à l'​endroit pose déhjà problème. Si la notion de sens n'a pas vraiment sa place dans le cas d'une table de hash, elle est tout à fait justifiée dans le cas d'une table indexée. Or s'il manque des éléments à une telle table, **ipairs** s'​arrêtera avant la fin. Écrire une fonction permettant effectivement de parcourir une table utilisée comme un tableau s’avère donc particulièrement laborieux.
 +<code lua>
 +foo = 42
 +baz = "​baz"​
 +test = {foo, bar, baz} -- bar est nil
 +test[5]="​test"​
 +test[10]="​test"​
 +print("​ipairs :")
 +for i, v in ipairs( test ) do -- La boucle n'​affiche que le premier élément
 +    print("​ - "​..i.."​ : "​..tostring(v))
 +end
 +print("​pairs :")
 +for k, v in pairs( test ) do -- La boucle affiche les éléments dans le désordre
 +    print("​ - "​..k.."​ : "​..tostring(v))
 +end
 +</​code>​
 +
 +=== Les fonctions à nombre d'​arguments variable ===
 +
 +En conséquence directe du point précédent,​ les fonctions à nombre d'​arguments variable sont susceptible de manquer des arguments dans le cas où l'un d'​entre eux est nil, comme le montre l'​exemple suivant, directement tiré de la documentation.
 +<code lua>
 +  function test(...)
 +      local printResult = ""​
 +      for i,v in ipairs(arg) do
 +        printResult = printResult .. tostring(v) .. "​\t"​
 +      end
 +      printResult = printResult .. "​\n"​
 +      print(printResult)
 +  end
 +
 +  test("​foo",​ nil, "​baz"​) -- N'​affiche que "​foo"​
 +</​code>​
 +
 +=== Les chaînes de caractères ===
 +
 +Lua ne permet pas d'​itérer dans des chaînes contrairement à la plupart des langages. Vouloir traiter une chaîne caractère par caractère nécessite de faire de lourdes opérations.
 +
 +En contrepartie il se veut 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.
 +
 +Les fonctions proposées par la bibliothèque standard sont de plus nommées de façon peu homogène :
 +  * **string.find** renvoie les indices de début et fin d'une sous-chaîne dans une chaîne
 +  * **string.sub** renvoie une sous-chaîne spécifiée par des indices
 +  * **string.gfind** renvoie les sous-chaînes correspondant à un motif
 +  * **string.gsub** remplace dans une chaîne un motif par une autre sous chaîne
 +Comme on le voit, le format de retour de **string.find** et **string.gfind** est différent, lorsque seul les arguments devraient l'​être,​ et **string.gsub** n'a tout simplement plus rien à voir.
 +
 +==== Problèmes d'​existence des données ====
 +
 +=== Portée globale par défaut ===
 +
 +Par défaut, tout élément est global. Si l'on souhaite limiter la portée au contexte dans lequel on se trouve, il faut le demander explicitement avec le mot clé **local**. Même un langage permissif comme le PHP considère que l'on souhaite une portée locale par défaut, et requiert une demande explicite pour avoir une portée globale.
 +
 +=== Création de variable implicite ===
 +
 +La création d'une variable est implicite, y compris pour une évaluation. Ainsi le code suivant est parfaitement valide :
 +<code lua>
 +bar = "​bar"​
 +foo = baz -- baz n'​existe pas, et l'​évaluation renvoie nil
 +</​code>​
 +
 +En pratique cela signifie qu'une faute de frappe dans le nom d'une variable ne sera détectée qu'à l'​exécution de la branche de code concernée.
 +
 +==== Problèmes de typage ====
 +
 +=== Typage dynamique ===
 +
 +Lua est typé dynamiquement,​ et une variable peut parfaitement recevoir successivement des valeurs de types différents.
 +
 +On ne peut poser aucune contrainte sur le type d'un élément, par exemple dans le cas des arguments d'une fonction, mais juste le vérifier à l'​exécution,​ ce qui coûte une comparaison de chaînes de caractères.
 +
 +=== Pas d'​opérateur booléen ===
 +
 +Lua dispose dans sa syntaxe d'​opérateurs **and** et **or**, mais ceux-ci ne sont certainement pas booléens. Il acceptent en effet toute valeur (comme expliqué plus haut, on ne peut pas imposer un type attendu), et renvoient celle des deux qui est déterminante,​ et ont donc  un type de retour dépendant des arguments.
 +
 +=== Pas de const ===
 +
 +Lua ne permet pas de définir des constantes, et plus généralement il n'​existe aucune notion de protection des données : n'​importe qu'​elle partie du code peut faire n'​importe quoi avec les données de n'​importe quelle autre partie.
 +
 +=== Du faux objet ===
 +
 +Lua ne propose pas le paradigme objet nativement. Certains traits du langage permettent de donner l'​illusion d'une programmation objet, et plusieurs bibliothèques se veulent capables d'​apporter cette fonctionnalité au langage. Mais en pratique, la bibliothèque Yaci par exemple, qui est pourtant la plus aboutie, souffre de gros défauts :
 +  * Le constructeur d'une super classe doit être appelé explicitement.
 +  * L'​espace de nom est différent entre une classe mère et sa classe fille, et si la classe fille a accès aux éléments de la classe mère, l'​inverse n'est pas vrai. Cela pourrait sembler naturel, mais a en pratique a pour conséquence que si l'on n'​initialise pas tous les membres de la classe mère dans son constructeur,​ ils vont être créés implicitement à la première affectation dans une méthode, et donc dans l'​espace de nom de la classe depuis laquelle la méthode aura été appelée. S'il s'​agissait d'une classe fille, la classe mère les verra non initialisés et ne pourra pas les manipuler. Pire : si, dans le cas courant d'une méthode surchargée par exemple, on appelle explicitement une méthode de la classe mère et que cette dernière affecte un membre, deux membres vont coexister, l'un dans la classe mère, l'​autre dans la classe fille.
 +  * Encore une fois il n'y a pas de notion de protection des données en Lua, et donc toute distinction entre donnée publique et privée est impossible. Au mieux on peut s'​interdire de manipuler des attributs depuis l'​extérieur d'une classe, mais en pratique rien ne l'​empêche,​ et surtout pas une faute de frappe.
 +
 +Ces différents points ont pour conséquence que l'​héritage est finalement absent de cette tentative d'​objet. Il est donc possible d'​avoir un code plus organisé et plus propre qu'une écriture purement impérative,​ mais il ne faut pas croire un seul instant qu'il s'agit là d'​objet.
lua.txt · Dernière modification: 2013/05/06 14:28 (modification externe)