230 likes | 404 Views
Interpretando objetos. Gustavo Betarte Grupo de Métodos Formales - LCC InCo. Contenido. Lenguajes basados en objetos El lenguaje FOb y el sistema UFOb El c álculo Un intérprete Conceptos definidos: funciones, naturales, clases y herencia Ejemplo: Calculadora
E N D
Interpretando objetos Gustavo Betarte Grupo de Métodos Formales - LCC InCo
Contenido • Lenguajes basados en objetos • El lenguaje FOb y el sistema UFOb • El cálculo • Un intérprete • Conceptos definidos: funciones, naturales, clases y herencia • Ejemplo: Calculadora • Trabajo futuro y conclusiones
Lenguajes basados en objetos • Características básicas • existencia de mecanismos para creación de objetos • ausencia de clases • prototipos y cloning (similar a new pero opera sobre objetos) • Implementan: • noción de objeto • despacho dinámico • si son tipados: • tipos de objetos • subtipado • subsumption
Lenguajes basados en objetos (cont.) • ObjectType Cell is • var contents : Integer; • method get() : Integer; • method set(n:Integer); • end; • object cell : Cell is • var contents : Integer := 0; • method get() : Integer is • return self.contents end; • method set(n:Integer) is • self.contents := n end; • end;
El lenguaje FOb • Es un lenguaje basado en objetos funcional • Estrategia de reducción “perezosa” • No tipado • Provee: • construcción de objetos primitivos • selección de campos e invocación de métodos • actualización de campos y métodos • funciones y aplicación • aritmética y booleanos
El lenguaje FOb: sintaxis concreta • <obj> ::= • <ident> | identificador • [l1 = <method>, … ,ln = <method>] | objeto • <obj>.l | selección / invocación • <obj>.l := <obj> | act. de campo • <obj>.l <- <method> | act. de método • \ <ident> -> <obj> | abstracción • <obj> <obj> | aplicación • if <boolexp> then <obj> else <obj> | • <arithexp> | <boolexp> | (<obj>) • <method> ::= (<ident>)<obj> • <ident> ::= String
El sistema UFOb • Evaluador de objetos FOb • Ambiente incremental de definición de objetos • Funcionalidades adicionales: parsing, compilación, carga de archivo de definiciones, despliegue de ambiente, recuperación de definiciones, etc. • Interfase XEmacs (modo .fob) • Implementado en Haskell 1.4 (compilado en hbc de Chalmers)
El Cálculo • Es un cálculo puro y no tipado de objetos. • A continuación resumimos la notación a ser usada para objetos y métodos: • (x)b método con parámetro self x y cuerpo b • [l1 = (x1)b1 … ln = (xn)bn] objeto con métodos li, i 1..n • o.l invocación de método l del objeto o • o.l (x)b actualización del método l de o con método (x)b • Campos no forman parte del cálculo (método con parámetro self dummy).
Sintaxis • Un término es una expresión generada por la siguiente gramática: • e::= x variable • [l1 = (x1)b1 … l2 = (x2)b2] formación de objeto • e.l sel. de campo / invoc. de método • e1.l (x)b actualización de campo / método • Se define como FV(e) al conjunto de variables libres de un término e. • La sustitución de las ocurrencias libres de un identificador x en el término b por un término c se denotará b[x:=c]
Semántica operacional • Definimos ahora un sistema determinístico de reducción para los términos cerrados del cálculo . Este sistema describe una estrategia de evaluación débil, en el sentido de que no se reducen cuerpos de métodos. • ------------------------------------------------ (red-obj) • [li = (xi)bi i 1..n ] [li = (xi)bi i 1..n ] • a v1 v1 [li = (xi)bi i 1..n ] bj [xj := v1] v2 • --------------------------------------------------------------------- (red-sel) • a.lj v2 • a [li = (xi)bi i 1..n ] • --------------------------------------------------------- (red-update) • a.lj (x)b [lj = (x)b, li = (x)bi i (1..n) - {j}]
Un intérprete • Las reglas que definen a la relación sugieren naturalmente un algoritmo de reducción, el que puede entenderse como un intérprete para términos cerrados. • El algoritmo, que definiremos recursivamente y llamaremos Eval, toma como argumento un término cerrado y, si converge, produce un resultado (un objeto primitivo). Si no, retornará error, que representa un error de computación. • Eval(c) denotará el resultado de correr el algoritmo sobre la entrada c.
Eval ([li = (xi)bi i 1..n ]) = [li = (xi)bi i 1..n ] • Eval (a.lj) = • let o = Eval (a) • in case o of • [li = (xi)bi i 1..n ] -> Eval (bj[xj := o]) • otherwise -> error • Eval (a.lj <- (x)b) = • let o = Eval (a) • in case o of • [li = (xi)bi i 1..n ] -> • [lj = (x)b, li = (x)bi i (1..n) - {j}] • otherwise -> error
Funciones como objetos • Es posible incorporar los términos del cálculo l en el cálculo de objetos. De hecho este cálculo es el llamado l presentado también en Abadi y Cardelli. • Nosotros hemos preferido, sin embargo, mantener el conjunto de primitivas del cálculo lo más reducido posible. • Traducción de términos l a objetos • x = x • b a = ( b .arg := a ).val • \x -> b = • [arg = (x)x.arg, • val = (x)( b [x := x.arg])]
Funciones como objetos (cont.) • La idea clave de la traducción es que una aplicación b a primero carga el argumento a en al campo arg de b , y luego invoca al método val de b, el que puede acceder al argumento a través de self. • Por ejemplo: • (\x -> x) 5 • = • ([arg = (x)x.arg, val = (x)x.arg].arg := 5).val • • [arg = (_)5, val = (x)x.arg].val • • 5
Naturales como objetos • En forma similar a la codificación de naturales en cálculo l, conocida como los numerales de Church, presentaremos ahora la codificación de naturales como términos del cálculo . • zero = [case = (_)\z -> \s -> z, • succ = (x)x.case := \z -> \s -> s x] • one = zero.succ • => [case = (_)\z -> \s -> s zero, • succ = (x)x.case := \z -> \s -> s z] • iszero = \n -> n.case true (\x -> false) • pred = \n -> n.case zero (\x -> x)
Traits, clases y herencia • Las nociones de trait, clase y herencia no aparecen explícitas en el cálculo. A continuación discutiremos cómo pueden ser representadas en términos de objetos puros. • Llamaremos pre-métodos a aquellas funciones que una vez embebidos en objetos se tornan métodos. • Se entenderá que herencia significa reutilización de pre-método y que traits y clases son colecciones de pre-métodos reusables interdependientes. • La reutilización de un método (x)b se logrará convirtiéndolo primero en un pre-método \x -> b, y luego embebiendo repeditamente esta función en objetos.
Representando Traits y Clases • Untrait es una colección de pre-métodos. • Si o [li = (s)bi i 1..n]es un objeto, entonces • t [li = \s -> bi i 1..n]es un trait parao. • Una clase será representada por medio de un trait y un método new, este último usado para generar objetos: • c = [ new = (z)[li = (s)z.li s i 1..n], • li = (_)\s -> bi i 1..n] • o = c.new • => • [li = (s)c.li s i 1..n]
Ejemplo: la clase Cell • class cell is • var contents : Integer:= 0; • method get(): Integeris • return self.contents; • method set(n:Integer) is • self.contents := n; • end; • Puede ser reformulada en como el objeto • clasCell = • [new = (z)[contents = (s)z.contents s, get = … , • set = (s)z.set s], • contents = \s -> 0, • get = \s -> s.contents, • set = \s -> \n -> s.contents := n]
Representando Herencia • Herencia consiste en reutilizar pre-métodos. Por ejemplo, c1, es una clase que reusa todos los pre-métodos de c y agrega además otros pre-métodos. Informalmente c1 es una subclase de c: • c1 = [ new = (z)[li = (s)z.li s i 1..n], • li = (_)c.lii 1..n, • lk = (_)\s -> bk k n+1..n+m] • La clasec2es una “subclase” de c que hereda los primeros n-1 pre-métodos de cy sobreescribe el último (notar super). • c2 =[ new = (z)[li = (s)z.li s i 1..n], • li = (_)c.lii 1..n, • ln = (_)\s -> ...c.ln s... c.lp s ...]
Ejemplo: la clase reCell • subclass reCell of cell is • var backup : Integer := 0; • override set(n:Integer) is • self.backup := self.contents; • super.set(n); • end; • method restore() isself.contents := self.backup end; • clasReCell = • [new = (z)[contents = (s)z.contents s, get = … ] • contents = classCell.contents, get = classCell.get, • set = \s -> \n -> • classCell.set (s.backup:=s.contents) n, • backup = \s -> 0 , • restore = \s -> s.contents := s.backup]
Ejemplo: Una calculadora • calc = • [arg = 0, • acc = 0, • enter = (s)\n -> s.arg := n, • add = (s)(s.acc := s.equals).equals • <- (s’)s’.acc + s’.arg, • sub = (s)(s.acc := s.equals).equals • <- (s’)s’.acc - s’.arg, • equals = (s)s.arg] • i) calc.enter(5).equals • ii) calc.enter(5).sub.enter(3).equals • iii) calc.enter(5).add.add.equals
Trabajo futuro?? • Implementar • chequeo de tipos • versión imperativa de FOb • en un lenguaje OO (Java, C++, …) • Extender • clases y herencia • subtipos • Entender • alto orden • compilación
Conclusiones • Se estudió e implementó conjunto básico de conceptos. Herramienta para experimentar y extender. • Cálculo reducido, nociones primitivas entendibles. • Herramienta téorica adecuada (“buenas” propiedades). • Excelencia de Haskell para prototipación (30 hs.).