Differences

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

Link to this comparison view

Next revision
Previous revision
teaching:cc4101:tareas:2025-1:tarea3 [2025/06/18 19:19] – created dibanezteaching:cc4101:tareas:2025-1:tarea3 [2025/06/19 21:09] (current) – [Tarea 3 (Entrega: TBD)] dibanez
Line 1: Line 1:
-====== Tarea 3 (Entrega: TBD) ====== +====== Tarea 3 (Entrega: 6 de Julio de 2025) ====== 
  
-Esta tarea se distribuye con un archivo zip (<<PLACEHOLDER>>) que contiene 3 archivos: main.rkt, tests.rkt y env.rkt. Los archivos están incompletos, y en ellos tiene que implementar lo que se solicita en las preguntas siguientes. +Esta tarea se distribuye con un archivo zip ({{ :teaching:cc4101:tareas:2025-1:t3-init.zip |}}) que contiene 3 archivos: main.rkt, tests.rkt y env.rkt. Los archivos están incompletos, y en ellos tiene que implementar lo que se solicita en las preguntas siguientes. 
  
 Debe entregar via U-cursos **un archivo .zip** que contenga los archivos main.rkt y tests.rkt. Debe entregar via U-cursos **un archivo .zip** que contenga los archivos main.rkt y tests.rkt.
Line 7: Line 7:
 <note important>Consulte las normas de entrega de tareas en http://pleiad.cl/teaching/cc4101</note> <note important>Consulte las normas de entrega de tareas en http://pleiad.cl/teaching/cc4101</note>
  
-**Recuerde que el testing y calidad de código se evalúan de acuerdo a [[https://docs.google.com/document/d/1Ahtk97_teZwtpFnJ-H--rLndeiFuyeDHpoGWpC8wL5I/edit?usp=sharing|la rúbrica]].**+**Recuerde que el testing y calidad de código se evalúan de acuerdo a [[https://docs.google.com/document/d/1Ahtk97_teZwtpFnJ-H--rLndeiFuyeDHpoGWpC8wL5I/edit?usp=sharing|esta rúbrica]].**
  
 ====== Resumen ====== ====== Resumen ======
  
-El objetivo de la tarea es extender un lenguaje base para soportar clases y objetos. El lenguaje base tiene números, booleanos y operaciones sobre ellos. Además contiene expresiones ''begin'' y ''with'' para secuenciar expresiones y definir múltiples identificadores respectivamente; pero no tiene soporte para funciones. Tome un tiempo de experimentar con el lenguaje entregado antes de comenzar a implementar las extensiones requeridas. +El objetivo de la tarea es extender un lenguaje base para soportar clases y objetos. El lenguaje base tiene números, booleanos y operaciones sobre ellos. Además contiene expresiones ''begin'' y ''with'' para secuenciar expresiones y definir múltiples identificadores respectivamente; pero no tiene soporte para funciones. Tome un tiempo de experimentar con el lenguaje entregado antes de comenzar a implementar las extensiones requeridas. 
- +
  
-La tarea está dividida en secciones,  las cuales se describen a continuación:+La tarea está dividida en secciones,  las cuales se describen a continuación:
  
 - **Clases y objetos**: En esta sección se pide extender el lenguaje base con clases y objetos. En particular las clases deben ser entidades de primera clase, es decir, son valores del lenguaje. - **Clases y objetos**: En esta sección se pide extender el lenguaje base con clases y objetos. En particular las clases deben ser entidades de primera clase, es decir, son valores del lenguaje.
  
 - **Codificando funciones anónimas de primera clase con Objetos**: El objetivo de esta sección es extender el lenguaje para soportar funciones anónimas de primera clase (típicamente conocidas como “lambdas”) y aplicaciones como azúcar sintáctica, usando objetos. - **Codificando funciones anónimas de primera clase con Objetos**: El objetivo de esta sección es extender el lenguaje para soportar funciones anónimas de primera clase (típicamente conocidas como “lambdas”) y aplicaciones como azúcar sintáctica, usando objetos.
 +
 +- **Campos de Clase (extra)**: Aquí se extendiende el lenguaje con campos mutables de clase, los que son accesibles desde la clase misma y compartidos entre todas las instancias.
  
 <note warning>  <note warning> 
Line 28: Line 29:
 (*) nada de ''(lambda (msg . args) ...)'' en su código! (*) nada de ''(lambda (msg . args) ...)'' en su código!
 </note> </note>
-===== Clases y objetos (5 ptos.) =====+===== Parte 1. Clases y objetos =====
 A continuación se presenta la sintaxis concreta del lenguaje extendido (se omiten las expresiones del lenguaje base):  A continuación se presenta la sintaxis concreta del lenguaje extendido (se omiten las expresiones del lenguaje base): 
 <code scheme> <code scheme>
Line 51: Line 52:
   * ''def'' permite definir un método, donde se especifica el nombre del método, 0 o más parámetros, y el cuerpo del método.   * ''def'' permite definir un método, donde se especifica el nombre del método, 0 o más parámetros, y el cuerpo del método.
  
-A lo largo de la implementación, verificaremos que los programas del lenguaje cumplan múltiples requisitos. Por ejemplo, revisaremos que no hayan campos duplicados dentro de una clase, o que los usos de ''self'' estén sólo dentro de un método. Todas las verificaciones que puedan hacerse de manera estática estarán centralizadas en una función llamada ''well-formed''. En el archivo base ''main.rkt'' se entrega una implementación inicial que deberá extender siguiendo las indicaciones del enunciado.+A lo largo de la implementación, verificaremos que los programas del lenguaje cumplan múltiples requisitos. Por ejemplo, revisaremos que no hayan campos duplicados dentro de una clase, o que los usos de ''self'' estén sólo dentro de un método. Todas las verificaciones que puedan hacerse de manera estática estarán centralizadas en una función llamada ''well-formed''. En el archivo base ''main.rkt'' se entrega una implementación inicial que incluye tanto la nueva sintaxis como sus parsers, deberá extenderla siguiendo las indicaciones del enunciado.
  
 Veamos algunos programas de ejemplo para ilustrar de manera general las características esperadas del lenguaje. Veamos algunos programas de ejemplo para ilustrar de manera general las características esperadas del lenguaje.
Line 108: Line 109:
  
 ==== Clases (1.5 pts) ==== ==== Clases (1.5 pts) ====
- 
-**Extensiones del AST y Parser** 
-  * [0.1 pts] Defina el tipo de datos ''Method'' para representar una definición de método en el AST. 
-  * [0.1 pts] Implemente la función ''parse-method'' que recibe una definición de método en sintaxis concreta y retorna el nodo de AST correspondiente. 
-  * [0.2 pts] Extienda el tipo de datos ''Expr'' y la función ''parse'' para soportar la expresión ''class'' del lenguaje. 
  
 **Extensiones de ''well-formed''** **Extensiones de ''well-formed''**
Line 125: Line 121:
  
 <code scheme> <code scheme>
-;; Crear una clase con campos duplicados es un error en tiempo de creación de la clase+;; Crear una clase con campos duplicados es un error estático.
 > (run-val '{begin {with {{A {class {x y x}}}} > (run-val '{begin {with {{A {class {x y x}}}}
                      10}                      10}
Line 133: Line 129:
  
 <code scheme> <code scheme>
-;; Tener 2 init con la misma aridad es un error en tiempo de creación de la clase+;; Tener 2 init con la misma aridad es un error estático.
 > (run-val '{begin {with {{A {class {x} > (run-val '{begin {with {{A {class {x}
                                {def init {init-x} {set x init-x}}                                {def init {init-x} {set x init-x}}
Line 143: Line 139:
  
 <code scheme> <code scheme>
-;; Tener 2 métodos con la misma aridad es un error en tiempo de creación de la clase+;; Tener 2 métodos con la misma aridad es un error estático.
 > (run-val '{begin {with {{A {class {x} > (run-val '{begin {with {{A {class {x}
                                {def foo {a} {set x a}}                                {def foo {a} {set x a}}
Line 158: Line 154:
 </code> </code>
  
-  * [0.7 pts] Extienda ''well-formed'' para realizar las verificaciones mencionadas.+  * [1 pt] Extienda ''well-formed'' para realizar las verificaciones mencionadas.
  
-**Observación**: Puede añadir un parámetro extra a ''well-formed'' para indicar si esta dentro de una clase+**Observación**: Puede añadir un parámetro extra a ''well-formed'' para indicar si se encuentra dentro de una clase
  
 **Intérprete** **Intérprete**
-  * [0.pts] Extienda el tipo ''Val'' con un constructor llamado ''classV'' que permita almacenar la información necesaria para representar a una clase como valor.+  * [0.pts] Extienda el tipo ''Val'' con un constructor llamado ''classV'' que permita almacenar la información necesaria para representar a una clase como valor.
   * [0.1 pts] Extienda el intérprete para soportar la creación de clases.   * [0.1 pts] Extienda el intérprete para soportar la creación de clases.
  
-**Observación**: Recuerde que los métodos definidos en una clase deben utilizar el ambiente al momento de la creación de la clase y no el ambiente de cuando son invocados.+**Observación**: El lenguaje implementa alcance léxico, por esto los métodos definidos en una clase deben utilizar el ambiente al momento de la creación de la clase y no el ambiente de cuando son invocados.
  
 ==== Objetos (1.5 pts) ==== ==== Objetos (1.5 pts) ====
 +En esta parte vamos a implementar ''new'' en ''well-formed'' e ''interp''.
  
-**Extensiones del AST Parser** +''{new cls arg1 arg2 arg3 ...}'' instancia la clase ''cls'' dejando los campos sin initializar, luego llama al constructor, recordar que los constructores son métodos llamados ''init'' puede estar sobrecargadoLa cantidad de argumentos pasados a ''new'' decidirá el constructor a usar. 
-  * [0.2 pts] Extienda el tipo de datos ''Expr'' y la función ''parse'' para soportar la expresión ''new'' del lenguaje.+ 
 +Si ''new'' es ejecutado sin argumentos, es decir, ''{new cls}'' y no existe un constructor que reciba 0 argumentos, entonces el resultado es un objeto con todos los campos sin inicializar.
  
 **Extensiones de ''well-formed''** **Extensiones de ''well-formed''**
-  * [0.2 pts] Extienda ''well-formed'' para verificar el nodo ''new''. En este caso, sólo es necesario llamar ''well-formed'' para cada subnodo del nodo ''new''.+  * [0.2 pts] Extienda ''well-formed'' para verificar el nodo ''new''. En este caso, sólo es necesario llamar recursivamente ''well-formed'' para cada subnodo del nodo ''new''.
  
 **Intérprete** **Intérprete**
   * [0.3 pts] Extienda el tipo ''Val'' con un constructor llamado ''objV'' que permita almacenar la información necesaria para representar a un objeto como valor. **Hint**: Recuerde que uno de los objetivos de tener clases, es permitir que sus intancias puedan compartir métodos.   * [0.3 pts] Extienda el tipo ''Val'' con un constructor llamado ''objV'' que permita almacenar la información necesaria para representar a un objeto como valor. **Hint**: Recuerde que uno de los objetivos de tener clases, es permitir que sus intancias puedan compartir métodos.
-  * [0.pts] Defina la función ''invoke-method'' que permita buscar un método dentro de la clase un objeto e invocarlo utilizando los argumentos entregados. +  * [0.pts] Defina la función ''invoke-method'' que permita buscar un método por nombre dentro de la clase de un objeto e invocarlo utilizando los argumentos entregados. Usted debe decidir la firma de esta función
-  * [0.pts] Extienda el intérprete para permitir instanciar una clase utilizando la expresión ''new''.+  * [0.pts] Extienda el intérprete para permitir instanciar una clase utilizando la expresión ''new''.
  
 **Observación**: Cuando se evalúa una expresión ''new'', se debe buscar en la clase un constructor que corresponda al número de argumentos entregados. Si no hay ninguno que tenga la aridad requerida, se debe lanzar el error ''"constructor not found"''. Si se está instanciando una clase que no declara ningún constructor, solo se puede usar el constructor por defecto que no recibe argumentos, es decir, ''{new c}''. **Observación**: Cuando se evalúa una expresión ''new'', se debe buscar en la clase un constructor que corresponda al número de argumentos entregados. Si no hay ninguno que tenga la aridad requerida, se debe lanzar el error ''"constructor not found"''. Si se está instanciando una clase que no declara ningún constructor, solo se puede usar el constructor por defecto que no recibe argumentos, es decir, ''{new c}''.
Line 196: Line 194:
 <code scheme> <code scheme>
 ;; Esta clase no tienen ningún constructor con aridad 2 ;; Esta clase no tienen ningún constructor con aridad 2
-> (run-val '{begin {with {{C {class {x} +> (run-val '{with {{C {class {x} 
-                               {def init {init-x} {set x init-x}}}}} +                             {def init {init-x} {set x init-x}}}}} 
-                     10} +                  {new C 1 2}})
-                   {new C 1 2}})+
 "error: constructor not found" "error: constructor not found"
 </code> </code>
  
 +<code scheme>
 +> (run-val '{with {{A {class {x y}
 +                             {def init {x y} {begin {set x x}
 +                                                    {set y y}}}}}}
 +                  {init A}})
 +; Retorna una instancia donde x e y no están inicializados.
 +</code>
 ==== Llamados a Métodos (0.8 pto) ==== ==== Llamados a Métodos (0.8 pto) ====
- 
-**Extensiones del AST y Parser** 
-  * [0.2 pts] Extienda el tipo de datos ''Expr'' y la función ''parse'' para soportar la expresión ''->'' del lenguaje. 
  
 **Extensiones de ''well-formed''** **Extensiones de ''well-formed''**
-  * [0.pts] Extienda ''well-formed'' para verificar el nodo ''->''. En este caso, solo es necesario llamar ''well-formed'' para cada subnodo del nodo ''new''.+  * [0.pts] Extienda ''well-formed'' para verificar el nodo ''->''. En este caso, solo es necesario llamar ''well-formed'' para cada subnodo del nodo ''new''.
  
 **Intérprete** **Intérprete**
-  * [0.pts] Extienda el intérprete para permitir evaluar la invocación de métodos de un objeto.+  * [0.pts] Extienda el intérprete para permitir evaluar la invocación de métodos de un objeto.
  
 **Observaciones**: **Observaciones**:
   * Recuerde en en la sección anterior (Objetos) implementó la función ''invoke-method''.   * Recuerde en en la sección anterior (Objetos) implementó la función ''invoke-method''.
-  * La invocación de un método inexistente o cuya aridad no coincide con el número de argumentos entregados debe lanzar el error ''"method <id> not found"''.+  * La invocación de un método inexistente debe lanzar el error ''"method <id> not found"''
 +  * Invocar un método con la cantidad equivocada de argumentos debe lanzar el error ''no overload of <num> arguments was found for method <id>''
  
 A continuación se muestran programas en los que se intenta invocar un método inexistente o donde no se encuentra una sobrecarga con la aridad correcta: A continuación se muestran programas en los que se intenta invocar un método inexistente o donde no se encuentra una sobrecarga con la aridad correcta:
Line 234: Line 236:
                    {o {new A}}}                    {o {new A}}}
               {-> o set-x 10 20}})               {-> o set-x 10 20}})
-"error: method set-x not found"+"error: no overload of 2 arguments was found for method set-x"
 </code> </code>
  
 ==== Acceso y Modificación a Campos (1.2 pts) ==== ==== Acceso y Modificación a Campos (1.2 pts) ====
- 
-**Extensiones del AST y Parser** 
-  * [0.2 pts] Extienda el tipo de datos ''Expr'' y la función ''parse'' para soportar la expresión ''get'' del lenguaje. 
-  * [0.2 pts] Extienda el tipo de datos ''Expr'' y la función ''parse'' para soportar la expresión ''set'' del lenguaje. 
  
 **Extensiones de ''well-formed''** **Extensiones de ''well-formed''**
Line 259: Line 257:
  
 **Intérprete** **Intérprete**
-  * [0.pts] Extienda el intérprete para permitir obtener el valor de un campo en una clase+  * [0.pts] Extienda el intérprete para permitir obtener el valor del campo de un objeto
-  * [0.pts] Extienda el intérprete para permitir modificar el valor de un campo en una clase.+  * [0.pts] Extienda el intérprete para permitir modificar el valor del campo de un objeto.
  
 Los errores dentro de ''interp'' para objetos deben manejarse de la siguiente forma: Los errores dentro de ''interp'' para objetos deben manejarse de la siguiente forma:
Line 282: Line 280:
 </code> </code>
  
-===== Codificando funciones anónimas de primera clase con Objetos (1 pto) =====+===== Parte 2: Codificando funciones anónimas de primera clase con Objetos (1 pt) =====
 Ahora incorporaremos funciones anónimas de primera clase (típicamente conocidas como "lambdas") a nuestro lenguaje. A diferencia de lo visto durante el curso, en esta ocasión no daremos una interpretación directa de las funciones. Usted debe idear una manera de usar la implementación de clases y objetos hecha en la parte anterior para codificar las lambdas. Esto significa que **no puede modificar** el AST y el intérprete para soportar funciones y aplicaciones de funciones. Las modificaciones que debe hacer son en el **parser**. En otras palabras, las funciones y aplicaciones serán sólo azúcar sintáctica. Ahora incorporaremos funciones anónimas de primera clase (típicamente conocidas como "lambdas") a nuestro lenguaje. A diferencia de lo visto durante el curso, en esta ocasión no daremos una interpretación directa de las funciones. Usted debe idear una manera de usar la implementación de clases y objetos hecha en la parte anterior para codificar las lambdas. Esto significa que **no puede modificar** el AST y el intérprete para soportar funciones y aplicaciones de funciones. Las modificaciones que debe hacer son en el **parser**. En otras palabras, las funciones y aplicaciones serán sólo azúcar sintáctica.
  
Line 303: Line 301:
 8 8
 </code> </code>
 +
 +===== Parte 3 (extra): Campos de Clase (1 pt de Bonus) =====
 +En la parte 1 implementamos clases con campos y métodos de instancia, además de estos la mayoría de lenguajes que permiten POO soportan campos y métodos de clase, como también campos y métodos estáticos.
 +
 +En esta parte extenderemos el lenguaje con campos de clase, para ello modificaremos la sintáxis de esta forma:
 +<code scheme>
 +<expr> ::= ... (expresiones del lenguaje base) ...
 +        | {class {<field>*} <method>*} 
 +
 +<field> ::= <sym>
 +          | {cls <sym> <expr>?}
 +</code>
 +
 +El ''?'' indica que un campo de clase puede o no incluir una expresión. Esta expresión es usada como valor inicial para el campo de clase.
 +
 +Tenga en consideración:
 +
 +  * Un campo de clase solo puede ser modificado por objetos de esa clase.
 +  * Un campo de clase puede ser leído usando ''get'' directamente sobre el valor de la clase, o desde cualquiera de sus instancias.
 +  * No pueden haber campos de clase o instancia con el mismo nombre. Esto debe comprobarse de forma estática. En caso de encontrarse, debe lanzar el error "duplicate fields"
 +  * Si un campo de clase no incluye un valor inicial, entonces se encuentra no inicializado. Intentar acceder a un campo de clase no inicializado debe lanzar el error "class field <id> not initialized".
 +
 +Programas de ejemplo:
 +<code scheme>
 +> (run-val '{with {{A {class {x {cls y 0}}
 +                             {def init {x}
 +                               {begin {set x x}
 +                                      {set y {+ 1 {get self y}}}}}}}
 +                   {o1 {init A 5}}
 +                   {o2 {init A 10}}
 +                   {o3 {init A 0}}}
 +                  {get A y}})
 +3
 +</code>
 +
 +<code scheme>
 +; Programa con un mismo nombre como campo de clase e instancia.
 +> (run-val '{with {{Foo {class {x {cls x}}}}}
 +                  0})
 +"error: duplicate fields"
 +</code>
 +
 +<code scheme>
 +; Programa que intenta leer un campo de clase no inicializado
 +> (run-val '{with {{Bar {class {cls a} {def get-a {} {get self a}}}}
 +                   {o {init Bar}}}
 +                  {-> o get-a}})
 +"error: class field a not initialized"
 +</code>
 +
 +<code scheme>
 +> (run-val '{with {{Test {class {cls b} {def set-b {new-b} {set b new-b}}}}
 +                   {o1 {init Test}}
 +                   {o2 {init Test}}
 +                  {begin {-> o1 set-b #t}
 +                         {get o2 b}}})
 +#t
 +</code>
 +
 +  * Realize las modificaciones necesarias para extender el lenguaje con campos de clase.
 +