viernes, 25 de noviembre de 2022

Primeros cambios en el interior PSeInt (2da parte)

Repito el comienzo del último post: "hay tres grandes objetivos: unificar algoritmos repetidos, eliminar todo el estado global, y separar/independizar los más posible las etapas del proceso de análisis e interpretación". En aquel me centraba en el primero, en este cuento cómo van los otros dos.


Se supone que todos sabemos lo malas que son las variables globales, pero probablemente también sabemos lo cómodas que son a veces. En pseint (el módulo) hay muuucho estado global, empezando por el perfil del lenguaje, las opciones de ejecución, información del control de errores, entradas predefinidas, etc.

Esto se debe, en parte a que cuando las puse ahí hace más de 10 años no era tan consiente de lo que implicaba, y a que en el diseño inicial el módulo se ejecutaba una sola vez por cada prueba/análisis de un algoritmo. Si ahora quiero colocar esta funcionalidad en una biblioteca para invocarla desde los otros módulos todas las veces que sea necesario, no es bueno tanto estado global, no es claro cómo reiniciarlo entre invocaciones, y no podría tener instancias paralelas (por ej. en el editor cuando hay varios algoritmos abiertos).

https://www.monkeyuser.com/2018/reminiscing/

Los principales puntos de entrada a lo que podría ser en un futuro esta biblioteca son dos o tres funciones clave, asociadas a las distintas etapas de la interpretación. Si quiero que las funciones tengan acceso a todo lo que necesitan, la gran parte que ahora es global debería convertirse en argumentos. Pero esto es molesto, porque hay muchas cosas (habría que agregar 10 argumentos a cada llamada), y porque estas funciones a su vez usan muchas otras pequeñas funciones auxiliares que tendrían el mismo problema.

Una solución que me pareció ingeniosa a nivel código (no a nivel diseño orientado a objetos) fue convertir las funciones en métodos de una clase, y hacer que todo lo que antes era global, ahora sea atributo de la clase. De esta forma, el trabajo extra está en invocar a un constructor pasándole toda esa información, pero si los atributos tienen los mismos nombres que tenían las variables globales, las funciones al convertirse en métodos de la clase ni siquiera cambian su código.

Parecía una idea simple. Intenté armar una clase para cada paso clave del intérprete: una que verifica la sintaxis, otra que ejecuta las instrucciones, otra que evalúa las expresiones, etc. Pero las interdependencias entre esas clases hicieron que se empiece a complicar. Por ejemplo, analizar la sintaxis actualmente requiere evaluar expresiones, para determinar su tipo y verificar el uso correcto de las variables y operadores. Pero el evaluador depende de la ejecución (si la expresión incluye la llamada a una función del usuario por ej). Y entonces la etapa de análisis requiere de la etapa de ejecución, cuando debería ser previa e independiente.

No me voy a meter en muchos más detalles, pero de estas relaciones circulares extrañas hay varias, y complican bastante la separación en clases y especialmente el uso (no quiero tener que declarar instancias de todas cuando necesite el resultado de solo una).

https://www.monkeyuser.com/2019/end-of-the-line

Así que volví a la idea de que todas las funciones reciban el estado que les interesa como parámetro. Pero, para simplificar los prototipos, escondí todo el estado global importante dentro de una clase Runtime, y ese es entonces el único argumento nuevo para casi todo. Cualquier cosa que vaya sacando del ámbito global, si es importante (mucho no lo era, o no ameritaba estar en todos lados), se irá mudando a ese Runtime.

Y por cosas globales no solo me refiero a variables. Por ejemplo, las funciones para reportar errores también eran globales. Y si quiero utilizar este código luego para mostrar los errores en tiempo real en el editor o en el diagrama, entonces necesito poder cambiar esas funciones, redireccionar los errores. Por esto dentro del Runtime agregué una instancia de una clase ErrorHandler, y todas las funciones globales para reportar errores pasaron a ser métodos virtuales en esta clase. Así, cuando el editor inicialice su propio Runtime, podrá inyectar su propio código para procesar los mensajes de error que se generen. Lo mismo tendré que hacer con otras cosas, como por ej la entrada/salida del usuario en la ejecución.

Y en esto estoy actualmente. Todavía trabajando solo en pseint, preparando las cosas para que cada modulo que necesite funcionalidad del mismo deje de tener que reimplementarla o invocarlo como proceso separado, con todo lo que eso implica (aunque no todo es malo), y pase a invocarlo como cualquier función de biblioteca.

P.D.: No puedo dejar de recomendar esta pag con comics para desarrolladores que acabo de encontrar: https://www.monkeyuser.com/

8 comentarios:

  1. Pardon the English, as I don't know Spanish. I know someone who teaches algorithms in French, and is looking for a replacement for LARP, seemingly quite similar to this project. If you can handle the multi-language process they might be interested in helping. I cannot supply contact details, as I have none, but you can investigate this source: https://cseducators.stackexchange.com/q/7580/104 and maybe answer their question with a reference to your project.

    ResponderEliminar
    Respuestas
    1. In its current state it is very very difficult to make it multi-language, I don't recommend trying. But it is one of the goals I have in mind while rewriting it. I hope it will be a lot easier in the future, but there's still a lot of work to be done in order to get there.

      Eliminar
    2. bro really, just use a true programming language, Pseint is just pseudcode por kids, if i can say that, :/

      Eliminar
  2. No sé qué decir, solo que Argentina gane la copa Mundial de fuchibou 2022

    ResponderEliminar
  3. Man, acabo de descargar motogt, sos increible.

    ResponderEliminar
  4. Por favor, agregar a PSeInt la posibilidad de tratar a las cadenas como arreglos de caracteres.

    ResponderEliminar
  5. al menos pon Pseint en ingles, cuando pasas a un lenguaje de verdad jode mucho

    ResponderEliminar