Lua à Moscou 2019: entretien avec Roberto Jérusalem



Il y a quelque temps, Roberto de Jérusalem, auteur de la langue Lua, a visité notre bureau de Moscou. Nous l'avons interviewé, au cours duquel nous avons posé des questions aux lecteurs de Habr. Enfin, nous pouvons partager avec vous l'intégralité de l'enregistrement de la conversation.

- Philosophisons pour commencer. Si vous deviez reconstruire Lua à partir de zéro, quelles trois choses changeriez-vous dans cette langue?

- Ouah! Question difficile. Il y a toute une histoire derrière la création et le développement de la langue. Ce n'était pas une grosse décision. Il y a des décisions que j'ai regrettées et que j'ai pu corriger au fil des ans. Et les programmeurs s'en plaignent tout le temps car la compatibilité est rompue. Nous l'avons fait plusieurs fois. Et je ne pense qu'à quelques petites tâches.

- Valeurs par défaut globales (Global par défaut)? Pensez-vous que c'est la bonne façon?

- Peut-ętre. Mais ce chemin est très difficile pour les langues dynamiques. Vous devriez peut-être abandonner complètement le concept de "défaut", mais il sera alors difficile d'utiliser des variables.
Par exemple, vous devez en quelque sorte déclarer toutes les bibliothèques standard. Vous avez besoin d' one-liner , print(sin(x)) , puis vous devez déclarer «print» et un autre «sin». C'est étrange d'avoir des publicités pour des scripts aussi courts.

Tout ce qui est plus gros ne devrait rien avoir par défaut, comme il me semble. Local-by-default n'est pas une solution, il n'existe pas du tout. C'est uniquement pour l'affectation, pas pour l'utilisation. Nous attribuons quelque chose, puis utilisons et attribuons à nouveau, et une erreur complètement inexplicable se produit.

Peut-être que la globalité par défaut n'est pas parfaite, mais la localité par défaut n'est certainement pas une option. Je pense qu'une sorte d'annonce, peut-être facultative ... Nous avons eu plusieurs fois l'intention de faire une sorte d'annonce mondiale. Mais si nous introduisons aveuglément tout ce qu'on nous demande, rien de bon n'en sortira.

(sarcastique) Oui, nous allons introduire une annonce globale, ajouter que, sho, cinquième, dixième, en retirer une autre, et par conséquent, nous réalisons que la solution finale ne satisfait pas la plupart des programmeurs, et nous n'ajouterons pas toutes les fonctionnalités qui nous sont demandées, et donc nous n'implémentons rien. Après tout, le mode strict est un compromis raisonnable.

Il y a un problème: le plus souvent, nous utilisons, par exemple, les champs à l'intérieur des modules, et là encore vous rencontrez les mêmes problèmes. Ce n'est là qu'un cas d'erreurs très spécifique, qui devrait probablement être pris en compte dans la solution générale. Donc, si vous en avez vraiment besoin, il est préférable d'utiliser un langage typé statiquement.

- La globalité par défaut est toujours pratique pour les petits fichiers de configuration.

"Oui, c'est vrai, pour les petits scripts et autres."

- Et pas de compromis dans ce cas?

- Il y a toujours des compromis. Dans ce cas, un compromis entre de petits scripts et de vrais programmes, quelque chose comme ça.

- Et ici, nous revenons à la première grande question: quelles trois choses changeriez-vous s'il y avait une telle opportunité? Il me semble que vous êtes assez satisfait de l'état actuel des choses, non?

"Eh bien, je n'appellerais pas cela un grand changement, et pourtant ... L'une des décisions infructueuses qui sont devenues un grand changement est nulle dans les tableaux." J'en suis désolé. J'ai fait ce hack ... Tu sais de quoi je parle? Il y a six mois ou un an, j'ai sorti une version de Lua dans laquelle il n'y avait rien dans les tableaux.

- Des valeurs nulles?

- Exactement. Je pense que cela s'appelle zéro dans les tableaux - c'est-à-dire nul. Nous avons fait un hack de grammaire pour assurer la compatibilité.

- Pourquoi est-il nécessaire?

«Je suis vraiment convaincu que c'est tout le problème ... Je pense que la plupart des problèmes avec zéro dans les tableaux disparaîtraient si nous pouvions avoir [zéro dans les tableaux] ... Plus précisément, le problème n'est pas avec zéro dans les tableaux. Ils me disent que les tableaux ne peuvent pas avoir zéro, donc les tableaux doivent être séparés des tables. Le vrai problème est que nous ne pouvons pas garder zéro dans les tableaux! Par conséquent, le problème n'est pas de savoir comment nous représentons les tableaux, mais dans les tableaux. Si nous pouvions avoir nil dans les tableaux, alors nous aurions nil dans les tableaux sans tout le reste. Je suis donc très désolé à ce sujet, et beaucoup de gens ne comprennent pas comment les choses auraient pu changer si Lua avait permis que rien ne soit placé dans les tables.

- Puis-je vous raconter une histoire sur Tarantool? Nous avons notre propre implémentation de null, qui est un CDATA vers un pointeur null. Nous l'utilisons dans les cas où vous devez créer des fragments vides dans votre mémoire pour insérer des arguments de positionnement pour les appels distants, etc. Mais généralement, c'est un problème car CDATA est toujours converti en vrai. Et zéro dans les tableaux résoudrait beaucoup de problèmes.

- Oui je sais. C’est de cela que je parle - cela résoudrait beaucoup de problèmes pour beaucoup, mais cela conduit à un problème de compatibilité encore plus important. Nous n'avons pas le courage de publier une version qui sera si incompatible, puis de détruire la communauté et de publier d'autres documents pour Lua 5, Lua 6, etc. Mais peut-être qu'un jour nous publierons une telle version. Ce seraient de très gros changements. Je crois que cela aurait dû être fait dès le début, et ensuite nous aurions parlé d'un changement trivial dans la langue, sauf pour la compatibilité. Et aujourd'hui, il va casser de nombreux programmes.

- Quelles lacunes voyez-vous en dehors du problème de compatibilité?

- Deux nouvelles fonctions primitives seront nécessaires. Quelque chose comme «Supprimer la clé», car l'attribution de nil ne supprimera pas la clé, vous aurez donc besoin d'une opération primitive pour la supprimer de la table. Et vous aurez besoin d'un «test» pour vérifier exactement où il y a une différence entre zéro et le manque de données.

- Avez-vous analysé l'impact de ces innovations dans les implémentations pratiques?

- Oui, nous avons sorti une telle version de Lua. Comme je l'ai dit, cela a brisé tranquillement le code. Certains utilisent l'appel de fonction table.insert(f(x)) . Et intentionnellement fait pour que si la fonction ne veut rien insérer, elle retourne nil. Ainsi, au lieu d'une vérification distincte, "Est-ce que je veux intégrer?" J'appelle table.insert , et si j'obtiens zéro, alors je sais qu'il ne sera pas inséré. Comme dans toute autre langue, le bogue est devenu une fonctionnalité et les gens l'utilisent. Mais si vous changez la fonctionnalité, cela cassera le code.

- Et le type de vide? Comme rien, seulement vide?

"Eh bien, non, c'est un cauchemar." Vous retardez simplement la résolution du problème. Si vous entrez une «béquille», vous en aurez besoin d'une de plus, de plus et de plus. Ce n'est pas une solution. L'un des problèmes est que le néant a déjà pris racine dans de nombreux endroits de la langue. Voici un exemple typique: nous disons «évitez le zéro dans les tableaux, c'est-à-dire les trous». Et puis nous écrivons une fonction qui retourne nil et quelque chose après, et nous obtenons un code d'erreur. Une telle construction implique déjà elle-même ce que nil est ... Par exemple, si je veux faire une liste des résultats retournés par la fonction, juste pour les attraper tous.

- Pour cela, vous avez un hack :)

"C'est vrai, mais vous n'êtes pas obligé d'utiliser des hacks pour résoudre des tâches aussi simples et évidentes." Cependant, les bibliothèques le font ... D'une certaine manière, j'y ai pensé: peut-être que les bibliothèques devraient retourner false au lieu de nil, bien que ce soit une option grossière, cela ne résoudra qu'une petite partie du problème. Le vrai problème, comme je l'ai dit, c'est que nous devons avoir zéro dans les tableaux. Sinon, nous ne devrions pas utiliser nil aussi souvent que je le pense. En général, ce n'est pas clair. Donc, si vous avez créé void, ces fonctions renverront toujours nil et nous ne résoudrons pas le problème tant que nous n'aurons pas créé un nouveau type et que les fonctions renverront void au lieu de nil.

- En utilisant void, vous pouvez explicitement dire que la clé doit être stockée dans la table, la clé avec la valeur void. Et rien peut fonctionner comme avant.

"Oui, c'est ce que je veux dire." Toutes ces fonctions dans les bibliothèques doivent renvoyer void ou nil.

"Ils peuvent aussi retourner nul, pourquoi pas?"

- Parce qu'alors pour certains cas nous ne résoudrons pas le problème de l'impossibilité de capturer toutes les valeurs que la fonction retourne.

"Mais nous n'aurons pas la première clé, seulement la seconde."

- Non, il n'y aura pas de seconde, car le calcul sera mal effectué et un trou apparaîtra dans le tableau.

- Alors tu veux dire que tu as besoin d'une fausse métaméthode?

- Oui. J'en rĂŞve:

{f(x)}

Vous devez intercepter tous les résultats renvoyés par f(x) . Et puis je peux dire %x ou #x , et de cette façon je connais le nombre de résultats retournés. Voilà comment une langue normale devrait fonctionner. Donc, créer un vide ne résoudra pas le problème tant qu'il n'y aura pas de règle très stricte selon laquelle les fonctions ne retournent jamais nul. Mais alors pourquoi avons-nous même besoin de zéro? Peut-être vaut-il la peine d'y renoncer.

- Roberto, y aura-t-il un soutien beaucoup plus fort pour l'analyse statique à Lua? Comme Lua Check sur les stéroïdes? Bien sûr, je comprends que cela ne résoudra pas tous les problèmes. Vous avez dit que cette fonctionnalité apparaîtra dans la version 6.0, le cas échéant, non? Et si dans 5.x il y aura un outil puissant pour l'analyse statique - si des heures de travail y sont investies - cela aidera-t-il?

"Non, je crois qu'un outil d'analyse statique vraiment puissant s'appelle ... un système de type!" Si vous avez besoin d'un outil vraiment puissant, utilisez un langage de type statique comme Haskell, ou un type de langage avec des types dépendants. Ensuite, vous aurez certainement un puissant outil d'analyse.

"Mais alors je n'aurai pas Lua."

- C'est vrai, Lua est nécessaire pour ...

- Des incertitudes? J'aime bien ta photo avec une girafe sur les types statiques et dynamiques.

- Oui, ceci est ma dernière diapositive de la présentation.


La dernière diapositive de la présentation du discours de Roberto Jérusalem «Pourquoi Lua? (et pourquoi pas) »lors de la conférence Lua à Moscou 2019.

- Pour poser la question suivante, revenons à cette image. Si je comprends bien, vous pensez que Lua est un petit outil pratique pour résoudre des tâches pas très importantes.

- Non, je crois que vous pouvez résoudre de gros problèmes, mais sans impliquer d'analyse statique. Je crois aux tests de tout mon cœur. Soit dit en passant, je ne suis pas d'accord avec vous en ce qui concerne la couverture, que nous ne devrions pas poursuivre la couverture ... Je veux dire, je suis entièrement d'accord avec le point de vue que la couverture ne fournit pas de test complet, mais le manque de couverture ne permet pas du tout de tester. J'ai parlé à Stockholm de la salle de test, vous y étiez. J'ai commencé à tester avec [plusieurs] bogues - c'est la chose la plus étrange - l'un d'eux était largement connu, et les autres étaient complètement inconnus. Quelque chose s'est complètement cassé dans le fichier d'en-tête Microsoft, C et C ++. J'ai fouillé le net, mais personne ne s'en inquiétait ni ne le remarquait.

Par exemple, il existe une fonction mathématique modf () , à laquelle il faut passer un pointeur vers une valeur double, car elle renvoie deux doubles. Nous convertissons l'entier ou la partie fractionnaire d'un nombre. Cette fonctionnalité fait depuis longtemps partie de la bibliothèque standard. Puis vint C 99, et cette fonction est maintenant nécessaire pour les nombres flottants. Et le fichier d'en-tête Microsoft a simplement enregistré cette fonction et en a déclaré une autre en tant que macro. Autrement dit, la première fonction a subi une conversion de type implicite. Double a été converti en flotteur, puis un pointeur à double a été converti en pointeur en flotteur!

- Quelque chose ne va pas avec cette image.

- Il s'agit du fichier d'en-tête de Visual C ++ et Visual C 2007. Si vous appelez cette fonction une fois, avec tous les paramètres, puis vérifiez le résultat, il sera erroné, sauf s'il est 0. Toute autre valeur ne sera pas vraie. Vous ne pouvez jamais utiliser cette fonction. Couverture zéro. Et puis il y a eu beaucoup de discussions sur les tests ... Il suffit d'appeler la fonction une fois et de vérifier le résultat! Ce problème existe depuis longtemps, pendant de nombreuses années il n'a dérangé personne. Apple avait un bug très célèbre, quelque chose comme " if… what… goto… ok ". Quelqu'un a inséré une autre expression ici, et tout est devenu normal. Et puis ils ont beaucoup discuté de la nécessité de règles, de l'utilisation des accolades dans le style de code, etc. Personne n'a mentionné qu'il existe de nombreux autres «si». Personne ne l'a fait ...

- Il y a aussi un problème de sécurité, si je me souviens bien.

- C'est vrai. Après tout, ils ne testent que des situations confirmées. Ils ne testent pas tout de suite, car tout sera confirmé. Cela signifie que dans l'application qui vérifie la sécurité, il n'y a pas un seul test qui vérifierait l'échec de toute connexion, ou ce qui devrait y être refusé. Et tout le monde se demande si les supports sont nécessaires ... Nous avons besoin de tests, au moins de tests! Après tout, personne n'a même testé ce que j'entends par «revêtement». C'est incroyable, les gens ne font même pas de tests de base. Bien sûr, il serait très difficile de fournir une couverture avec des tests de base, d'exécuter toutes les lignes de code. Les gens évitent même les tests de base, la couverture est donc minimale. Je vous demande instamment de prêter attention aux parties du programme que vous avez oubliées. Quelque chose comme un indice pour améliorer un peu vos tests.

- Savez-vous quelle couverture de test Ă  Tarantool? 83%! Quelle est la couverture Ă  Lua?

- Environ 99,6%. Combien de lignes de code avez-vous? Un million, des centaines de milliers? C'est énorme. 1% de cent mille, c'est mille lignes de code qui n'ont jamais été testées. Vous ne les avez pas exécutées du tout. Vos utilisateurs ne testent rien.

- Autrement dit, environ 17% des fonctions de Tarantool ne sont pas utilisées actuellement?

- Il est peu probable que vous souhaitiez revenir à ce dont nous parlions à nouveau ... Je pense que l'un des problèmes avec les langages dynamiques (et les statiques aussi) est que les gens ne testent pas leur code. Même en utilisant un langage statique - pas comme Haskell, mais quelque chose comme Coq - jusqu'à ce que vous ayez un système de vérification, vous changerez ceci en cela. Et aucun outil d'analyse statique ne peut détecter ces erreurs, vous avez donc besoin de tests. Et si vous les avez, vous pouvez identifier les problèmes globaux, les fautes de frappe dans les noms, etc., toutes sortes d'erreurs. Vous avez certainement besoin de tests. Parfois, il sera difficile de déboguer, sinon c'est simple - cela dépend de la langue et du type de bogue. Mais l'essentiel est qu'aucun outil d'analyse statique ne peut remplacer les tests. En revanche, ils ne garantissent pas l'absence d'erreurs, mais avec eux je me sens beaucoup plus en confiance.

- Nous avons une question sur le test des modules Lua. En tant que développeur, je souhaite tester certaines fonctions locales que je pourrai utiliser plus tard. Question: vous avez besoin d'une couverture au niveau de 99%, mais le nombre de situations fonctionnelles que le module pour l'API devrait générer est bien inférieur à la quantité de fonctionnalités qu'il prend en charge en interne.

- Excusez-moi, pourquoi?

- Il existe des fonctionnalités qui ne sont pas disponibles pour les interfaces publiques.

"Elle ne devrait pas ĂŞtre lĂ , supprimez simplement ce code."

- Il suffit de le retirer?

- Oui, je le fais parfois à Lua. Il y avait une sorte de couverture de code, je ne pouvais pas arriver ici, là ou là, j'ai décidé que c'était impossible et j'ai juste supprimé le code. Rarement, mais ça arrive. Si certaines situations sont impossibles, écrivez simplement dans les commentaires pourquoi cela n'est pas possible. Si vous ne pouvez pas accéder à la fonction à partir de l'API publique, cela ne devrait pas l'être. Il est nécessaire d'écrire des API publiques avec des données d'entrée erronées, ceci est important pour les tests.

- La suppression du code est bonne, elle réduit la complexité. Moins de complexité - stabilité plus élevée et facilité d'entretien. Ne vous compliquez pas.

- Oui, dans la programmation extrême, il existe une telle règle. Si quelque chose ne peut pas être testé, il n'existe pas.

- Quelles langues t'as inspiré pour créer Lua? Quels paradigmes, caractéristiques fonctionnelles ou parties de langues que vous aimez?

- J'ai conçu Lua dans un but très étroit, ce n'était pas un projet académique. Alors quand vous m'avez demandé de recréer la langue, j'ai répondu qu'il y avait toute une histoire derrière. Je n'ai pas commencé à développer Lua avec "Je vais créer un langage que j'aime, ou que je veux utiliser, ou dont tout le monde a besoin." J'ai eu un problème: ici j'ai besoin d'un langage de configuration pour les géologues et les ingénieurs, il doit être petit et avec une interface simple pour qu'ils puissent l'utiliser. Par conséquent, l'API a toujours fait partie intégrante du langage. Telle était la tâche. Quant à l'inspiration, à cette époque, je connaissais une dizaine de langues différentes.

"Je me demande quelles langues vous voulez inclure dans Lua."

- J'ai emprunté des idées à de nombreuses langues, tout ce qui convenait pour résoudre mon problème. La syntaxe du langage Modula a eu la plus grande influence, bien qu'elle soit difficile à dire, car il y a tellement de langues. Quelque chose a pris à AWK. Bien sûr, de Scheme et Lisp ... Je ne suis pas indifférent à Lisp depuis que j'ai commencé la programmation.

- Et il n'y a toujours pas de macros Ă  Lua!

- Oui, la syntaxe est complètement différente. La première langue était probablement le Fortran ... non, ma première langue était l'assembleur, puis le Fortran. J'ai étudié, mais je n'ai jamais utilisé le CLU. Beaucoup programmé sur Smalltalk et SNOBOL. A également étudié, mais n'a pas utilisé Icon, également une langue très intéressante. J'ai beaucoup emprunté à Pascal et C. Quand j'ai créé Lua, le C ++ était déjà trop compliqué pour moi, c'était avant les templates et autres. J'ai commencé à travailler en 1991 et j'ai libéré Lua en 1993.

- L'URSS s'est effondrée et vous avez commencé à créer Lua :) Vous n'aimiez pas les points-virgules et les objets lorsque vous avez commencé Lua? Il me semblait que sa syntaxe serait similaire à C, car Lua y est intégré. Mais ...

- Je crois que la syntaxe doit être différente, alors vous ne vous tromperez pas, car ce sont deux langues différentes.

C'est vraiment drôle, et est lié à la réponse concernant les tableaux commençant par un, que vous ne m'avez pas permis d'exprimer [lors de la conférence]. Ma réponse était trop longue.

Quand Lua a été libéré, le monde était différent. Tous les langages n'étaient pas similaires à C. Il n'y avait toujours pas Java et JavaScript, Python était un bébé et ne dépassait pas la version 1.0. Donc, tous les langages n'étaient pas similaires à C; sa syntaxe était l'une des nombreuses.

Même chose avec les tableaux. C'est drôle que la plupart de cela ne soit pas au courant. Les tableaux commençant par 0 et 1 ont leurs propres mérites.

C'est grâce à C que les langages les plus populaires utilisent aujourd'hui des tableaux commençant par 0. Leurs créateurs ont été inspirés par C. Et c'est drôle qu'il n'y ait pas d'indexation en C. , , . , — , (offset). , , , , .

, , . Java, JavaScript — . 0, . , « ».

— , , . -, , , - , , . , Lua ? Pourquoi?

— ?

— .

— . , , . . ? , , . . .

— Lua C.

— , , . , , … , , - . : , … .

, . , ? , - … ?

— .

— . ? C , , … ?

— 16 ?

— , .

— , , .

— , . , , … , , . — , . , , . , … : ?

— C++ .

— , C++ .

— ? ptrdiff_t ?

— ptrdiff_t — (signed type). , , . ?

, diff , . . , ? Pas question. , , . 2 , .

, . , . diff , .

, ++.

— Lua ?

— , C++, - , . , - ++, … .

— , ?

— . , . , , . , .

— JVM?

— , JVM. , … — , . JVM , .NET, . JVM , Lua. , . JVM, . JVM . Java-, 10 . , JVM , .

— JVM, , Mobile JVM?

— , JVM. - Java, Java.

— , Go Oberon? Lua, ?

— Oberon… … Go , runtime- Lua. Oberon , . , , . , , const Pascal Oberon. , . .
, 1994- Oberon Self. Self? JIT- . Self , , . - , — ! — , - . , …

Oberon, , 10 Self, . Oberon , , .

, .

— Haskell?

— Haskell, , Lua.

— Python, R Julia Lua?

— , .

R . , .

Python , . , . , .

Python , , . , , - . API… , Python, . , , « ».

, -: , , , -. . , API , - . , . , , …

- , (pattern matching). , , , . , , .

: Perl. Lua, . , Python . , , . - .

— ?

— Python. Perl : $1, $2, $3. Perl, …

— Python, , ( Tarantool).

— , , , API, . Python , .

Julia, LuaJIT, , . , , . , . , , , . , , . : , - . , , - , .

Julia, : , , . , - . , double, []… . .

() «, , , , , . , ». , , .

. R, Python.

— Erlang?

— . , . , , , - . Erlang , , . , .

, . , . ? , . .

— , Erlang , Python . Lua?

— , . Lua , , Lua , .

— ?

— Forth, .

— Lua?

— , . , . - , . Lua, Lua, .

Java. Java, ? Non. (reflection)? Non. ? Java, , Java. , , Java, .

, Lua, … , , FFI.

— Lua?

— , .

— Lua ? ?

— , . , Haskell. , , … Lua, , , , , .

— , Lua.

— , , . . , .

— , . Lua ?

— , , …

— « »? , ?

— , . , , , . , .

— Lua?

— . , , LaTex DocBook. , … LaTex, . @, . Gsub , , - - . , , , .

— LaTeX?

— LaTeX? -, , . , , LaTex. , inline-. /, . — . , , , . , . , .

— LaTeX?

— , . , , . , 3+1, . , , . , . , , . , 1 «and», . . , .

— ?

— , git . 2html . HTML… , . , , . , , . , TeX. TeX- TeX.

— ?

— , . , TeX. , . DocBook, . , .

— 2html DocBook?

— , DocBook.

— , , !

— .



- , Lua Mailing List .

Source: https://habr.com/ru/post/fr459464/


All Articles