Lua en Moscú 2019: entrevista con Roberto Jerusalem



Hace algún tiempo, Roberto de Jerusalén, autor del idioma Lua, visitó nuestra oficina de Moscú. Lo entrevistamos, durante el cual le hicimos preguntas a los lectores de Habr. Finalmente, podemos compartir con usted toda la grabación de la conversación.

- Filosoficemos para empezar. Si construyeras Lua nuevamente desde cero, ¿qué tres cosas cambiarías en este idioma?

- Wow! Pregunta difícil Hay toda una historia detrás de la creación y el desarrollo del lenguaje. Esta no fue una gran decisión. Hubo decisiones de las que me arrepentí y que a lo largo de los años pude solucionar. Y los programadores se quejan de eso todo el tiempo porque la compatibilidad no funciona. Lo hemos hecho varias veces. Y solo pienso en algunas tareas pequeñas.

- Valores predeterminados globales (Global por defecto)? ¿Crees que esta es la forma correcta?

- tal vez. Pero este camino es muy difícil para los lenguajes dinámicos. Quizás debería abandonar por completo el concepto de "defecto", pero entonces será difícil usar variables.
Por ejemplo, debe declarar de alguna manera todas las bibliotecas estándar. Necesita one-liner , print(sin(x)) , y luego debe declarar "print" y otra "sin". Es extraño tener anuncios para scripts tan cortos.

Cualquier cosa más grande no debería tener nada por defecto, como me parece. Local por defecto no es una solución, no existe en absoluto. Es solo para asignación, no para uso. Asignamos algo, luego usamos y asignamos nuevamente, y se produce un error completamente inexplicable.

Quizás la globalidad predeterminada no sea perfecta, pero la localidad predeterminada definitivamente no es una opción. Creo que algún tipo de anuncio, tal vez opcional ... Hemos intentado muchas veces hacer algún tipo de anuncio global. Pero si presentamos ciegamente todo lo que se nos pide, no saldrá nada bueno.

(sarcásticamente) Sí, vamos a presentar un anuncio global, agregar que, sho, quinto, décimo, extraer otro, y como resultado, nos damos cuenta de que la solución final no satisface a la mayoría de los programadores, y no agregaremos todas las características que se nos solicitan, y por lo tanto No implementamos nada. Después de todo, el modo estricto es un compromiso razonable.

Hay un problema: la mayoría de las veces usamos, por ejemplo, los campos dentro de los módulos, y luego nuevamente tiene los mismos problemas. Este es solo un caso muy específico de errores, que probablemente debería tenerse en cuenta en la solución general. Entonces, si realmente lo necesita, es mejor usar un lenguaje estáticamente escrito.

- La globalidad predeterminada sigue siendo conveniente para archivos de configuración pequeños.

"Sí, cierto, para pequeños guiones y similares".

- ¿Y sin compromisos en este caso?

- Siempre hay compromisos. En este caso, un compromiso entre pequeños scripts y programas reales, algo así.

- Y aquí volvemos a la primera gran pregunta: ¿qué tres cosas cambiarías si tuvieras esa oportunidad? Me parece que estás bastante contento con el estado actual de las cosas, ¿verdad?

"Bueno, no lo llamaría un gran cambio, y sin embargo ... Una de las decisiones fallidas que se convirtió en un gran cambio es nula en las tablas". Lo siento por eso. Hice este truco ... ¿Sabes de lo que estoy hablando? C hace medio año o hace un año, lancé una versión de Lua en la que no había nada en las tablas.

- ¿Valores nulos?

- Exactamente Creo que esto se llama nulo en las tablas, es decir, nulo. Hicimos un hack de gramática para garantizar la compatibilidad.

- ¿Por qué es necesario?

"Estoy realmente convencido de que este es todo el problema ... Creo que la mayoría de los problemas con nil en matrices desaparecerían si pudiéramos tener [nil en tablas] ... Más precisamente, el problema no es con nil en arrays". Me dicen que las matrices no pueden tener cero, por lo que las matrices deben estar separadas de las tablas. ¡El verdadero problema es que no podemos mantener nulo en las tablas! Por lo tanto, el problema no es cómo representamos las matrices, sino en las tablas. Si pudiéramos tener nil en tablas, entonces tendríamos nil en matrices sin todo lo demás. Así que lo siento mucho, y muchas personas no entienden cómo podrían haber cambiado las cosas si Lua permitiera que nulo fuera colocado en las mesas.

- ¿Puedo contarte una historia sobre Tarantool? Tenemos nuestra propia implementación de nulo, que es un CDATA a un puntero nulo. Lo usamos en casos en los que necesita crear fragmentos vacíos en su memoria para insertar argumentos de posicionamiento para llamadas remotas, y así sucesivamente. Pero generalmente esto es un problema porque CDATA siempre se convierte en verdadero. Y nulo en matrices resolvería muchos problemas.

- Si lo se. De esto es de lo que estoy hablando: resolvería muchos problemas para muchos, pero esto lleva a un problema de compatibilidad aún mayor. No tenemos el coraje de lanzar una versión que sea tan incompatible, y luego destruir la comunidad y lanzar otra documentación para Lua 5, Lua 6, etc. Pero tal vez algún día lanzaremos tal versión. Estos serían cambios muy grandes. Creo que esto debería haberse hecho desde el principio, y luego habríamos hablado de un cambio trivial en el idioma, excepto por la compatibilidad. Y hoy romperá muchos programas.

- ¿Qué deficiencias ves además del problema de compatibilidad?

- Se requerirán dos nuevas funciones primitivas. Algo así como la "Clave de eliminación", porque asignar nil no eliminará la clave, por lo que necesitará una operación primitiva para eliminarla de la tabla. Y necesitará una "prueba" para verificar exactamente dónde hay una diferencia entre nulo y falta de datos.

- ¿Ha analizado el impacto de estas innovaciones en implementaciones prácticas?

- Sí, lanzamos una versión de Lua. Como dije, esto silenciosamente rompió el código. Algunos usan la table.insert(f(x)) la función table.insert(f(x)) . Y hecho intencionalmente para que si la función no quiere insertar nada, devuelve nil. Entonces, en lugar de una verificación por separado, "¿Quiero incrustar?" Llamo a table.insert , y si obtengo nil, sé que no se insertará. Como en cualquier otro idioma, el error se ha convertido en una característica, y la gente lo usa. Pero si cambia la función, se romperá el código.

- ¿Qué pasa con el tipo vacío? ¿Como nulo, solo vacío?

"Bueno, no, es una pesadilla". Simplemente pospones resolver el problema. Si ingresa una "muleta", necesitará una más, y más, y más. Esto no es una solución. Uno de los problemas es que nil ya ha echado raíces en muchos lugares del idioma. Aquí hay un ejemplo típico: decimos "evitar nulo en matrices, es decir, agujeros". Y luego escribimos una función que devuelve nil y algo después, y obtenemos un código de error. Tal construcción ya implica lo que es nulo ... Por ejemplo, si quiero hacer una lista de los resultados devueltos por la función, solo para atraparlos a todos.

- Para esto tienes un truco :)

"Eso es correcto, pero no es obligatorio usar hacks para resolver tareas tan simples y obvias". Sin embargo, las bibliotecas hacen esto ... De alguna manera lo pensé: quizás las bibliotecas deberían devolver falso en lugar de nulo, aunque esta es una opción cruda, resolverá solo una pequeña parte del problema. El verdadero problema, como dije, es que necesitamos tener nulo en las tablas. De lo contrario, no deberíamos usar nil tan a menudo como creo. En general, no está claro. Entonces, si creó void, estas funciones aún devolverán nil, y no resolveremos el problema hasta que creemos un nuevo tipo y las funciones devuelvan void en lugar de nil.

- Con void, puede decir explícitamente que la clave debe almacenarse en la tabla, la clave con el valor void. Y nada puede funcionar como antes.

"Sí, a eso me refiero". Todas estas funciones en las bibliotecas deben devolver void o nil.

"También pueden regresar cero, ¿por qué no?"

- Porque entonces, en algunos casos, no resolveremos el problema de la imposibilidad de capturar todos los valores que devuelve la función.

"Pero no tendremos la primera clave, solo la segunda".

- No, no habrá segundo, porque el cálculo se realizará incorrectamente y aparecerá un agujero en la matriz.

- ¿Entonces quieres decir que necesitas un metametodo falso?

- si. Sueño con esto:

{f(x)}

Debe interceptar todos los resultados devueltos por f(x) . Y luego puedo decir %x o #x , y de esta manera sé la cantidad de resultados devueltos. Así es como debería funcionar un lenguaje normal. Por lo tanto, crear un vacío no resolverá el problema hasta que haya una regla muy estricta que las funciones nunca devuelvan nulo. Pero entonces, ¿por qué necesitamos nada? Quizás valga la pena renunciar a él.

- Roberto, ¿habrá un apoyo mucho más fuerte para el análisis estático en Lua? ¿Te gusta Lua Check con esteroides? Por supuesto, entiendo que esto no resolverá todos los problemas. Usted dijo que esta característica aparecerá en la versión 6.0, si es que lo hace, ¿verdad? Y si en 5.x habrá una herramienta poderosa para el análisis estático, si se invierten horas hombre en él, ¿esto ayudará?

"No, creo que una herramienta de análisis estático realmente potente se llama ... ¡un sistema de tipos!" Si necesita una herramienta realmente poderosa, use un lenguaje de tipo estático como Haskell, o algún tipo de lenguaje con tipos dependientes. Entonces definitivamente tendrá una poderosa herramienta de análisis.

"Pero entonces no tendré a Lua".

- Así es, se necesita a Lua para ...

- ¿Incertidumbres? Me gusta tu foto con una jirafa sobre tipos estáticos y dinámicos.

- Sí, esta es mi última diapositiva de la presentación.


La última diapositiva de la presentación de la charla de Roberto Jerusalem "¿Por qué Lua? (y por qué no) "en la conferencia Lua en Moscú 2019.

- Para hacer la siguiente pregunta, volvamos a esta imagen. Si entiendo correctamente, piensas que Lua es una pequeña herramienta conveniente para resolver tareas no muy grandes.

- No, creo que puedes resolver algunos problemas importantes, pero que no implican análisis estático. Creo en las pruebas con todo mi corazón. Por cierto, no estoy de acuerdo con usted con respecto a la cobertura, que no debemos perseguir la cobertura ... Quiero decir, estoy completamente de acuerdo con la opinión de que la cobertura no proporciona pruebas completas, pero la falta de cobertura no permite la prueba en absoluto. Hablé en Estocolmo sobre la sala de pruebas, estabas allí. Comencé a probar con [varios] errores, esto es lo más extraño, uno de ellos era ampliamente conocido y el resto era completamente desconocido. Algo se rompió por completo en el archivo de encabezado de Microsoft, C y C ++. Busqué en la red, pero nadie estaba preocupado ni lo notó.

Por ejemplo, hay una función matemática modf () , que necesita pasar un puntero a un valor doble, porque devuelve dos dobles. Convertimos el entero o la parte fraccionaria de un número. Esta característica ha sido durante mucho tiempo parte de la biblioteca estándar. Luego vino C 99, y esta función ahora es necesaria para números flotantes. Y el archivo de encabezado de Microsoft simplemente guardó esta función y declaró otra como macro. Es decir, la primera función se sometió a una conversión de tipo implícita. ¡El doble se convirtió en un flotador, y luego un puntero al doble se convirtió en un puntero en un flotador!

- Algo está mal con esta imagen.

- Este es el archivo de encabezado de Visual C ++ y Visual C 2007. Si llama a esta función una vez, con algún parámetro, y luego verifica el resultado, será erróneo, a menos que sea 0. Cualquier otro valor no será verdadero. Nunca puedes usar esta función. Cero cobertura. Y luego hubo mucha discusión sobre las pruebas ... ¡Solo llame a la función una vez y verifique el resultado! Este problema existió durante mucho tiempo, durante muchos años no molestó a nadie. Apple tenía un error muy famoso, algo así como " if… what… goto… ok ". Alguien insertó otra expresión aquí, y todo se volvió normal. Y luego discutieron mucho sobre si se necesitaban reglas, si las llaves deberían usarse en el estilo del código, y así sucesivamente. Nadie mencionó que hay muchos otros "si". Nadie lo hizo ...

- También hay un problema de seguridad, según recuerdo.

Eso es correcto. Después de todo, solo prueban situaciones confirmadas. No prueban todo en una fila, porque todo se confirmará. Esto significa que en la aplicación que verifica la seguridad, no hay una sola prueba que verifique si hay fallas en las conexiones, o lo que debería negarse allí. Y todos discuten sobre si se necesitan los corchetes ... ¡Necesitamos exámenes, al menos exámenes! Después de todo, nadie probó lo que quiero decir con "recubrimiento". Esto es increíble, la gente ni siquiera realiza pruebas básicas. Por supuesto, sería muy difícil proporcionar cobertura con pruebas básicas, ejecutar todas las líneas de código. Las personas evitan incluso las pruebas básicas, por lo que la cobertura es mínima. Quiero instarlo a que preste atención a las partes del programa que olvidó. Algo así como una pista de cómo mejorar un poco tus pruebas.

- ¿Sabes qué cobertura de prueba en Tarantool? 83%! ¿Cuál es la cobertura en Lua?

- Alrededor del 99,6%. ¿Cuántas líneas de código tienes? ¿Un millón, cientos de miles? Esta es una gran cantidad. El 1% de cien mil son mil líneas de código que nunca se han probado. No los ejecutaste en absoluto. Sus usuarios no están probando nada.

- Es decir, ¿alrededor del 17% de las funciones de Tarantool no se usan ahora?

- Es poco probable que desee volver a lo que estábamos hablando de nuevo ... Creo que uno de los problemas con los lenguajes dinámicos (y también los estáticos) es que la gente no prueba su código. Incluso usando un lenguaje estático, no como Haskell, sino algo como Coq, hasta que tenga un sistema de verificación, cambiará esto a eso. Y ninguna herramienta de análisis estático puede detectar estos errores, por lo que necesita pruebas. Y si los tiene, puede identificar problemas globales, errores tipográficos en los nombres, etc., todo tipo de errores. Definitivamente necesitas pruebas. A veces será difícil depurar, de lo contrario es simple: depende del idioma y el tipo de error. Pero la conclusión es que ninguna herramienta de análisis estático puede reemplazar las pruebas. Por otro lado, no garantizan la ausencia de errores, pero con ellos me siento mucho más seguro.

- Tenemos una pregunta sobre cómo probar los módulos Lua. Como desarrollador, quiero probar algunas funciones locales que puedo usar más adelante. Pregunta: necesita una cobertura del 99%, pero la cantidad de situaciones funcionales que debe generar el módulo para la API es mucho menor que la cantidad de funcionalidad que admite internamente.

- Disculpe, ¿por qué?

- Hay una funcionalidad que no está disponible para las interfaces públicas.

"Ella no debería estar allí, simplemente borre este código".

- ¿Solo quitarlo?

- Sí, hago esto a veces en Lua. Hubo algún tipo de cobertura de código, no pude llegar aquí, allá o allá, decidí que era imposible y simplemente eliminé el código. Raramente, pero sucede. Si algunas situaciones son imposibles, solo escriba en los comentarios por qué esto no es posible. Si no puede acceder a la función desde la API pública, no debería serlo. Es necesario escribir API públicas con datos de entrada erróneos, esto es importante para las pruebas.

- Eliminar el código es bueno, reduce la complejidad. Menos complejidad: mayor estabilidad y facilidad de mantenimiento. No te compliques.

- Sí, en la programación extrema existe tal regla. Si algo no se puede probar, no existe.

- ¿En qué idiomas te inspiraste para crear Lua? ¿Qué paradigmas, características funcionales o partes de qué idiomas te gustan?

- Diseñé Lua para un propósito muy limitado, no era un proyecto académico. Entonces, cuando me preguntaste sobre volver a crear el lenguaje, respondí que había una historia completa detrás. No comencé a desarrollar Lua con "Crearé un lenguaje que me guste, que quiera usar o que todos necesiten". Tuve un problema: aquí necesito un lenguaje de configuración para geólogos e ingenieros, debe ser pequeño y con una interfaz simple para que puedan usarlo. Por lo tanto, la API siempre ha sido una parte integral del lenguaje. Esa fue la tarea. En cuanto a la inspiración, en ese momento estaba familiarizado con unos diez idiomas diferentes.

"Me pregunto qué idiomas quieres incluir en Lua".

- Tomé prestadas ideas de muchos idiomas, todo lo que era adecuado para resolver mi problema. La sintaxis del lenguaje Modula tuvo la mayor influencia, aunque es difícil de decir, porque hay muchos idiomas. Algo tomó de AWK. Por supuesto, de Scheme y Lisp ... No soy indiferente a Lisp desde que comencé a programar.

- ¡Y todavía no hay macros en Lua!

- Sí, la sintaxis es completamente diferente. Probablemente el primer idioma fue Fortran ... no, mi primer idioma fue ensamblador, y luego Fortran. Estudié, pero nunca usé el CLU. Programado mucho en Smalltalk y SNOBOL. También estudié, pero no usé Icon, también un lenguaje muy interesante. Tomé prestado mucho de Pascal y C. Cuando creé Lua, C ++ ya era demasiado complicado para mí, esto era antes de las plantillas y otras cosas. Comencé a trabajar en 1991 y lancé Lua en 1993.

- La URSS se derrumbó y comenzaste a crear Lua :) ¿No te gustaban los puntos y comas cuando comenzaste a usar Lua? Me pareció que su sintaxis sería similar a C, porque Lua está integrada en ella. Sin embargo ...

- Creo que la sintaxis debería ser diferente, entonces no te confundirás, porque estos son dos idiomas diferentes.

Esto es realmente divertido y está relacionado con la respuesta sobre las matrices que comienzan con una, que no me permitiste expresar [en la conferencia]. Mi respuesta fue muy larga.

Cuando Lua fue lanzado, el mundo era diferente. No todos los lenguajes eran similares a C. Todavía no había Java y JavaScript, Python era un bebé y no fue más allá de la versión 1.0. Entonces, no todos los lenguajes eran similares a C; su sintaxis era una de muchas.

Lo mismo con las matrices. Es curioso que la mayor parte de esto no sea consciente. Las matrices que comienzan con 0 y 1 tienen sus propios méritos.

Es gracias a C que los lenguajes más populares hoy en día usan matrices que comienzan con 0. Sus creadores se inspiraron en C. Y es curioso que no haya indexación en C. , , . , — , (offset). , , , , .

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

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

— ?

— .

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

— Lua C.

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

, . , ? , - … ?

— .

— . ? C , , … ?

— 16 ?

— , .

— , , .

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

— C++ .

— , C++ .

— ? ptrdiff_t ?

ptrdiff_t — (signed type). , , . ?

, diff , . . , ? De ninguna manera , , . 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, ? No (reflection)? No ? 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/459464/


All Articles