programacion - Operadores Lua, ¿por qué no se define+=,-= y así sucesivamente?
lua programacion (3)
Esta es una pregunta por la que he estado un poco irritado por algún tiempo y nunca he buscado la respuesta.
Sin embargo, pensé que al menos podría hacer la pregunta y quizás alguien pueda explicarme.
Básicamente, muchos idiomas en los que he trabajado utilizan azúcar sintáctica para escribir (usando la sintaxis de C ++):
int main() {
int a = 2;
a += 3; // a=a+3
}
mientras que en lua, el +=
no está definido, así que tendría que escribir a=a+3
, que una vez más es todo acerca del azúcar sintáctico. cuando se usa un nombre de variable más "significativo" como: bleed_damage_over_time
o algo, comienza a ser tedioso escribir:
bleed_damage_over_time = bleed_damage_over_time + added_bleed_damage_over_time
en lugar de:
bleed_damage_over_time += added_bleed_damage_over_time
Entonces, me gustaría saber cómo resolver esto si no tienes una buena solución, en ese caso, por supuesto, estaría interesado en escucharla; sino más bien por qué lua no implementa este azúcar sintáctico.
Creo que podrías volver a escribir esta pregunta como
¿Por qué
<languageX>
tiene<featureY>
de<languageZ>
?
Por lo general, es una solución de compromiso que los diseñadores de idiomas elaboran en función de su visión de a qué se destina el lenguaje y sus objetivos.
En el caso de Lua, el lenguaje está destinado a ser un lenguaje de scripting incorporado, por lo que cualquier cambio que haga que el lenguaje sea más complejo o potencialmente haga que el compilador / tiempo de ejecución sea aún un poco más grande o más lento puede ir en contra de este objetivo.
Si implementa todas y cada una de las funciones más pequeñas, puede terminar con un lenguaje de "fregadero de cocina": ADA , ¿alguien?
Y como dices, es solo azúcar sintáctico.
Esto solo es una conjetura de mi parte, pero:
1. Es difícil implementar esto en un compilador de un solo pase
El compilador de códigos de bytes de Lua se implementa como un analizador de descenso recursivo de un solo paso que genera código inmediatamente. No analiza una estructura AST separada y luego, en una segunda pasada, la convierte en bytecode.
Esto fuerza algunas limitaciones en la gramática y la semántica. En particular, cualquier cosa que requiera referencias anticipadas o arbitrarias es realmente difícil de respaldar en este modelo. Esto significa que las asignaciones ya son difíciles de analizar. Dado algo como:
foo.bar.baz = "value"
Cuando estás analizando foo.bar.baz
, no te das cuenta de que en realidad estás analizando una tarea hasta que tocas el =
después de haber analizado y generado el código para eso. El compilador de Lua tiene una gran complejidad solo para manejar las tareas debido a esto.
El apoyo a la autoasignación lo haría aún más difícil. Algo como:
foo.bar.baz += "value"
Necesita ser traducido a:
foo.bar.baz = foo.bar.baz + "value"
Pero en el momento en que el compilador toca el =
, ya se ha olvidado de foo.bar.baz
. Es posible, pero no es fácil.
2. Puede que no juegue bien con la gramática
Lua en realidad no tiene ninguna declaración o separadores de línea en la gramática. El espacio en blanco se ignora y no hay puntos y comas obligatorios. Tu puedes hacer:
io.write("one")
io.write("two")
O:
io.write("one") io.write("two")
Y Lua está igualmente feliz con ambos. Mantener una gramática como esa no ambigua es complicado. No estoy seguro, pero los operadores de autoasignación pueden hacer eso más difícil.
3. No funciona bien con asignaciones múltiples
Lua admite asignaciones múltiples, como:
a, b, c = someFnThatReturnsThreeValues()
Ni siquiera está claro para mí qué significaría si intentaras hacer:
a, b, c += someFnThatReturnsThreeValues()
Puede limitar los operadores de autoasignación a una sola asignación, pero luego acaba de agregar un caso de esquina extraño que las personas deben conocer.
Con todo esto, no está del todo claro que los operadores de autoasignación sean lo suficientemente útiles para valer la pena lidiar con los problemas anteriores.
Otra razón por la que Lua no tiene operadores de autoasignación es que el acceso a la tabla puede estar sobrecargado con metatablas para tener efectos secundarios arbitrarios. Para autoasignación necesitarás elegir desugar
foo.bar.baz += 2
dentro
foo.bar.baz = foo.bar.baz + 2
o en
local tmp = foo.bar
tmp.baz = tmp.baz + 2
La primera versión ejecuta el __index
__index para foo
dos veces, mientras que la segunda solo lo hace una vez. No incluir la autoasignación en el idioma y obligarlo a ser explícito ayuda a evitar esta ambigüedad.