Differences

This shows you the differences between two versions of the page.

Link to this comparison view

teaching:cc4101:tareas:2023-1:tarea2:parte1 [2023/05/11 15:22] – created tvallejosteaching:cc4101:tareas:2023-1:tarea2:parte1 [2023/05/11 16:23] (current) tvallejos
Line 1: Line 1:
 +[[teaching:cc4101:tareas:2023-1:tarea2|<< Volver]]
 +
 +===== Parte 1. Testing de efectos (2 ptos.) ===== 
 +En esta sección van a implementar un mecanismo para hacer tests sobre efectos secundarios, en particular, sobre la impresión de caracteres (//printing//). La necesidad de testear efectos secundarios es muy recurrente en proyectos reales, existiendo distintas técnicas para abordarlo (p.ej. usando [[https://en.wikipedia.org/wiki/Mock_object|mocks]]). En esta ocasión, implementarán una solución que utiliza alcance dinámico para redirigir la salida de impresión hacia una estructura de datos.
 +
 +<note important>
 +Asegúrense de haber estudiado la [[teaching:cc4101:tareas:2023-1:tarea2:parte0|introducción a SL y CL]] antes de proceder, en particular, la definición de CL (no usamos SL en esta pregunta).
 +</note>
 +
 +En comparación con lo visto en clases, CL cuenta con una nueva expresión ''{printn <CL>}'' que imprime el valor de la expresión en pantalla (usando ''println'' de Racket) y retorna el valor de la expresión. Por ejemplo, ejecutar ''{+ 1 {printn {+ 1 2}}}'' debe imprimir 3, y su valor es 4. 
 +
 +    * Escriba tests de ''printn'' y observe que no es posible chequear (con la función ''test'') que efectivamente se imprima, ni que los valores impresos sean los esperados.
 +
 +Para poder validar los valores impresos, van a utilizar una estrategia que consiste, en esencia, en redirigir la impresión desde la salida estándar hacia un //log//. Luego, los tests simplemente consisten en corroborar el estado del log. 
 +
 +==== Agregando logs: primer intento ====
 +
 +En un primer intento, van a agregar logs a través de una nueva estructura de datos y manteniendo un registro global de impresiones. En seguida, actualizarán su función de interpretación para que utilice este nuevo mecanismo. 
 +
 +Para esta sección y la siguiente, consideren la siguiente estructura, donde se mantiene tanto el valor de ejecución como el log de impresiones.
 +
 +<code scheme>
 +(deftype Result 
 +    (result val log))
 +</code>
 +
 +Por otro lado, para mantener un log les recomendamos utilizar el mecanismo de cajas de Racket ([[https://docs.racket-lang.org/reference/boxes.html|documentación]]). A continuación les proveemos una ilustración de la API de cajas, para hacer crecer una lista:
 +
 +<code scheme>
 +> (define log (box '())) ;; Crea una caja con valor inicial lista vacía
 +> (unbox log)  ;; Abre la caja y obtiene su valor guardado
 +'()
 +> (set-box! log (cons "hola" (unbox log)))  ;; Modifica el contenido de la caja
 +> (set-box! log (cons "chao" (unbox log)))  ;; Modifica el contenido de la caja
 +> (unbox log)
 +'("chao" "hola")
 +</code>
 +
 +Con estos dos elementos, van a reemplazar la función ''println'' utilizada en la interpretación de CL, de tal manera de poder rescatar la información de los valores impresos. A modo de preparación para la siguiente etapa, realice los siguientes pasos:
 +  * Defina una nueva función de impresión ''println-g'' que, dado un número, lo agrega a un log global (es decir, usen ''define'' para agregar un identificador global). 
 +  * Modifique ''interp'' para que use ''println-g'', en vez de ''println''.
 +  * Defina una función ''interp-g'', que dada una expresión, retorna un valor de tipo ''Result'' (usando ''interp''). La función debe reiniciar el log global en cada llamada.
 +  * Defina tests para verificar que efectivamente es capaz de testear la salida de las impresiones.
 +
 +Llegados a este punto, ¡ya son capaces de testear las impresiones de caracteres! Sin embargo, este enfoque tiene dos problemas importantes:
 +  - Ya no se imprime en pantalla m(.
 +  - El uso de un valor global no es adecuado en un contexto concurrente (p.ej. si se ejecutasen tests en paralelo, el log resultante sería impredecible e incorrecto).
 +
 +En lo que sigue verán cómo solucionar estos puntos.
 +
 ==== Segundo intento: alcance dinámico ==== ==== Segundo intento: alcance dinámico ====