Universidad de Granada E.T.S. Ingeniería Informática Eiffel Diego Montesinos Hervás Irene Díaz Valenzuela Andrés Herrera del Pino José Antonio Sáez Muñoz 3º Ingeniería Informática Programación Dirigida a Objetos Grupo B - Curso 2006-2007 1 1.Introducción 2 1.Introducción Eiffel es un lenguaje de programación orientado a objetos centrado en la construcción de software robusto. Diseñado por Bertrand Meyer, apareció en 1985 y fué desarrollado por Meyer y Eiffel Software. Eiffel es un lenguaje con tipos fuertes, pero relajado por herencia. Implementa administración automática de memoria, generalmente mediante algoritmos de recolección de basura. 3 1.1 Características esenciales - Mecanismos de ayuda al Diseño por contrato que se integraron firmemente con el mecanismo de herencia y otras construcciones del lenguaje. - Estructura de programa orientada a objetos, las clases son la unidad básica. - Asignación estática de tipos. - Ayuda para la gestión automática de memoria, implementada por el recolector de basura. - Papel central de la herencia, incluyendo herencia múltiple y mecanismo para hacerla segura. 4 1.1 Características esenciales - Un sistema uniforme de tipos que maneja las semanticas de referencia y valor, donde todos los tipos (incluyendo los tipos básicos) están basados en clases. - Tipos genéricos. - ‘Bloques‘(agent) (similares a los de Smalltalk) - Rutinas 'once' (evaluadas solamente la primera vez), para la compartición de objetos e inicialización. - Sintaxis basada en las palabras clave de ALGOL/Pascal pero sin separador (se puede usar el punto y coma, es 5 opcional). 1.2 Características de diseño - Eiffel enfatiza en sentencias declarativas sobre código procesal. - Eiffel evita los trucos de codificación o técnicas de codificación previstas. - Se intenta no sólo hacer código más legible, sino también permitir a los programadores concentrarse en los aspectos importantes del programa sin meterse en detalles de implementación. 6 1.2 Características de diseño –La simplicidad de Eiffel se ha pensado para promover respuestas simples, extensibles y reutilizables para los problemas de computación. –Los compiladores proveen técnicas de optimización con el objetivo de crear código extremadamente eficiente, comparable a C++, por ejemplo. –Al igual que los lenguajes de programación vistos en la asignatura, Eiffel también utiliza semántica en el heap. 7 2.Características de Eiffel 8 2.Características La meta del lenguaje, bibliotecas, y métodos de programación es crear un software que utilice módulos lo más reutilizables posible. 9 2.1 Eiffel soporta... Herencia múltiple: permite que una clase herede de varias superclases. Además posibilita a los subtipos adaptarse a sus propiedades heredades renombrándolas o estableciendo reglas de selección para ellas. ● 10 2.1 Eiffel soporta... Tipos genéricos: Eiffel usa tipos parametrizados (genéricos), como en otros lenguajes como Ada, Java, C#, que permiten definir un tipo sin especificar todos los otros tipos que usa. Los tipos no especificados son sustituidos por parámetros en estos puntos del código. ● 11 2.1 Eiffel soporta... Polimorfismo: capacidad que tienen objetos de diferentes clases de responder al mismo mensaje. Esto significa que puede haber muchos mensajes con el mismo nombre, en diferentes clases. Cada clase responde al mensaje con su código propio (método). ● 12 2.1 Eiffel soporta... Encapsulación : ocultamiento del estado, es decir, de los datos miembro, de un objeto de manera que sólo se puede cambiar mediante las operaciones definidas para ese objeto. ●De esta forma, el usuario de la clase puede obviar la implementación de los métodos y propiedades para concentrarse sólo en cómo usarlos. Por otro lado se evita que el usuario pueda cambiar su estado de maneras imprevistas e incontroladas. ● 13 2.1 Eiffel soporta... Asignación fuerte de tipos ●En LPs con tipos, una expresión de valores está bien formada cuando a su valor se le puede asignar un tipo, ya sea en tiempo de compilación o de ejecución. ●No se procede a la evaluación si no se ha podido determinar por inferencia dicho tipo ●Podríamos hablar de tipo de la expresión ●Los LPs en que las expresiones han de ser consistentes respecto a los tipos se dice que son LPs con asignación fuerte de tipos ● 14 2.1 Eiffel soporta... Equivalencia de métodos y tipos: como ya sabemos de otras asignaturas, en algunos LPs, si S es subtipo de T, podemos utilizar S donde se espere un parámetro de tipo T, y si una función devuelve un tipo T, podría devolver tipo S sin problema ninguno. ●Por extensión, donde corresponde una clase cualquiera, nos podemos encontrar con cualquier subclase suya. ● 15 2.2 Contribución de Eiffel Su contribución más importante a la ingeniería del software es el Diseño por Contracto (DbC), en el cual se tienen: ● − − − − Assertions(afirmaciones) Precondiciones Postcondiciones Invariantes de clase que son usadas para asegurar la corrección del programa sin sacrificar la eficiencia. 16 2.2 Contribución de Eiffel • Assertions(afirmaciones) En Eiffel, las afirmaciones son integradas en el lenguaje y son extraídas automáticamente para generar la documentación de la clase. 17 2.2 Contribución de Eiffel Una afirmación es un predicado (por ejemplo, una expresión booleana) situada en un programa para indicar que la afirmación es verdad en ese lugar. Por ejemplo, el siguiente código contiene dos afirmaciones: ●x:= 5; {x > 0} x:= x + 1 {x > 1} ●Se usan para ayudar a la especificación de programas y asegurar la corrección del código. ● 18 2.2 Contribución de Eiffel Algunos lenguajes de programación modernos incluyen la sentencia de afirmación (assert(cond)) que es una condición que se comprueba en tiempo de ejecución. Si la evaluación de la condición falla, se produce un fallo de afirmación como resultado, el cual puede causar que la ejecución se aborte o puede causar el reconsiderar una vía alternativa para el programa. ●El uso de afirmaciones ayuda al programador a diseñar, desarrollar y comprobar la corrección del código. Además permite hacer comprobaciones durante el proceso de pruebas, durante la ejecución, y detectar los posibles fallos, permitiendo al programador detectar bugs de sus programas. ● 19 2.2 Contribución de Eiffel Precondiciones: ●Es una afirmación (condición o predicado) que debe ser siempre verdadero al principio de la ejecución de alguna sección de código. ●Si la precondición falla, el efecto de la sección de código puede estar indefinido y puede que se produzcan errores en la ejecución. ●Ejemplo: para calcular el factorial de un número la precondición es que el número sea mayor o igual que 0. ● 20 2.2 Contribución de Eiffel Postcondiciones: ●Es una afirmación (condición o predicado) que debe ser siempre cierto justo después de la ejecución de un algún trozo de código. ●Ejemplo: Para una función que calcule el factorial, la poscondición puede ser que el resultado sea siempre mayor o igual que 1. ● 21 2.2 Contribución de Eiffel Invariante de representación. ●Es una serie de condiciones impuestas sobre los objetos de una clase que determinan si un objeto está o no bien formado. ●Los métodos de la clase deben preservar el invariante de representación. ●Los invariantes de representación son establecidos durante la construcción y continuamente se mantiene tras las llamadas a los métodos públicos. ● 22 2.2 Contribución de Eiffel El diseño de Eiffel está basado en la teoría de la programación orientada a objetos. ●El lenguaje tiene un soporte formal para tipos abstractos de datos. ●Bajo el correcto diseño de texto software se debe ser capaz de reproducir una documentación para el diseño final del software a partir de la información de la implementación que está formalizada para el “tipo abstracto de dato”. ● 23 2.3 Implementaciones y entornos • EiffelStudio es un entorno de desarrollo integrado (código libre o licencias comerciales). Es un entorno orientado a objetos que usa técnicas de interfaz de usurario como el pick-and-drop. • EiffelEnvision es un pluggin para Microsoft Visual Studio, que permite a los usuarios editar ,compilar y depurar programas en Eiffel al usar Microsoft Visual Studio IDE. 24 2.3 Implementaciones y entornos ● Existen dos implementaciones de código libre: − − ● ● SmartEiffel (implementacion GNU, basada en una versión anterior del lenguaje) Visual Eiffel. Originalmente, el lenguaje Sather estaba basado en Eiffel, pero fue modificándose, y ahora incluye varias características de la programación funcional. Parte de Apple Media Tool está basado en Eiffel. 25 2.4 Especificaciones y estándares El lenguaje Eiffel es un estándar internacional de la ISO (International Organization for Standardization). ● El estándar fue desarrollado por ECMA International y su primera versión fue aprobada por ECMA el 21 de Junio de 2005 como el standard ECMA 367 (Eiffel: Analysis, Design and Implementation Language) ● 26 2.4 Especificaciones y estándares ● ● ● La segunda edición fue adoptada por ECMA en Junio de 2006 y en el mismo año por la ISO (Noviembre de 2006). El desarrollo software de Eiffel y de sus bibliotecas, dio lugar a implementar un estándar; Eiffel Software's EiffelStudio 5.7, que implementa algunos de los mejores mecanismos del lenguaje. El equipo de SmartEiffel se apartó de este estándar para crear su porpia versión del lenguaje, el cual parece está más cerca del estilo original de Eiffel. 27 2.4 Especificaciones y estándares Bibliografía de especificación del lenguaje Eiffel: ● Bertrand Meyer: Eiffel: The Language, Prentice Hall, segunda edición, 1992 (primera edición: 1991) ● Bertrand Meyer: Standard Eiffel, 1997. ● Bertrand Meyer: Object-Oriented Software Construction, Prentice Hall: primera edición, 1988; segunda edición, 1997. ● 28 3.Cómo programar en Eiffel 29 3.Cómo programar en Eiffel Un programa en Eiffel es un conjunto de clases. Pueden definirse conjuntos de clases denominados cluster. Estos conjuntos pueden subdividirse en subclusters anidados Las clases contienen features que son similares a los métodos en otros lenguajes. En una clase se definen sus invariantes y contienen otras propiedades tales como las notes que es una sección para incluir la documentación. Los tipos de datos estándar son también clases. Todo sistema tiene una clase denominada root, que contendrá un constructor llamado root procedure. Para ejecutar un programa en Eiffel se debe crear una instancia de la clase root y ejecutar su root procedure. 30 3.Cómo programar en Eiffel Existen seis instrucciones básicas en Eiffel: asignación, creación de objetos, llamada a rutinas, condicional y selección. Para facilitar la abstracción de datos y el ocultamiento de información, Eiffel, igual que ocurría en SmallTalk no permite la asignación entre variables de instancia de los objetos, sino que necesita de una interfaz para manejar los datos. El concepto de “diseño por contrato” es central en Eiffel, sus mecanismos están muy integrados en el lenguaje. Las características del contrato se extienden por medio de la herencia. 31 3.1 Ejemplo de programa en Eiffel class HELLO_WORLD create make feature make is do io.put_string (“Hello World!”) io.put_new_line end end 32 3.2 Descripción de una clase Una clase contiene un conjunto de feature (métodos). Como las clases representan un conjunto de objetos, un feature es una operación sobre estos objetos. Estas pueden ser de dos tipos: ● Consultores, que dan información sobre una instancia Órdenes que modifican una instancia. Esta distinción es importante en los métodos de Eiffel. En particular: ● Principio de Acceso Uniforme: desde el exterior cualquier consultor es un atributo o el resultado de una operación. La notación es la misma en ambos casos. Principio de separación entre las órdenes y consultores. Esto no es una regla del lenguaje, pero se entiende como una buena práctica de programación que no se realicen cambios en el mismo. 33 3.3 Sobrecarga Eiffel soporta la sobrecarga de funciones y operadores, es decir, los nombres de funciones pueden volver a usarse en diferentes clases, pero siempre haciendo referencia al mismo comportamiento. ●Para hacer uso de esta funcionalidad simplemente tenemos que asignar el mismo nombre a distintos feature en las distintas clases implicadas. Veamos un ejemplo con el operador + a + b for a,b: INTEGER a + b for a,b: REAL a + b for a,b: VECTOR [INTEGER] ●Sin embargo, Eiffel no soporta la sobrecarga de funciones dentro de una misma clase como ocurre en otros lenguajes como C++, por tanto, las funciones f (x: X) y f(y: Y) no podrían convivir en la misma clase. ● 34 3.4 Genéricos Pueden definirse clases genéricas que usen parámetros. Estos parámetros genéricos aparecen entre paréntesis. ● class LIST [G]..●G es llamado parámetro formal genérico. En la declaración, G representa un tipo arbitrario, por tanto, una función podrá devolver un valor de tipo G y una rutina usarlo como argumento. item: G do ... end put (x: G) do ... end 35 3.4 Genéricos ● ● También es posible tener parámetros formales limitados, para los que el parámetro actual debe heredarse de una clase dada. Por ejemplo en class HASH_TABLE [G, KEY -> HASHABLE] una derivación HASH_TABLE [INTEGER, STRING] sólo es válida si STRING hereda de HASHABLE. Teniendo KEY limitada por HASHABLE significa que para x: KEY podremos aplicarle a x todos los métodos de HASHABLE. 36 3.5 Herencia Para heredar de una o más clases, se debe incluir la palabra reservada inherit al principio: ● class C inherit A B ... Rest of class declaration ... 37 3.5 Herencia ● Una clase puede sobrecargar alguno de los features heredados. Esto debe aparecer explícitamente en la declaración, usando la palabra reservada redefine en la clausula de herencia class C inherit A redefine f, g, h end B redefine u, v end 38 3.6 Clases y métodos abstractos Las clases pueden definirse como deferred class en lugar de como class para indicar que esas clases no pueden ser instanciadas. Es lo que en otros lenguajes se conoce como clases abstractas. ● Un método o feature puede ser igualmente abstracto colocando la palabra deferred en lugar de una clausula do. Si una clase tiene algún método deferred debe declararse como tal, aunque también pueden hacerlo clases que no los contengan. ● 39 3.7 Renombramiento Cuando una clase hereda de una o más clases, toma todos sus métodos con los nombres originales. Es posible en este lenguaje renombrarlos haciendo uso de la palabra reservada rename. ● Esto es especialmente necesario en el caso de la herencia múltiple, pues puede darse el caso de colisiones entre métodos de distintas clases, lo cual violaría el principio de “no sobrecarga” de nombres dentro del mismo método, devolviendo un error. ● 40 3.8 Tuplas El tipo tupla puede verse como una forma simple de clase, dando solo atributos y el correspondiente constructor. Un ejemplo típico sería: ● TUPLE [name: STRING; peso: REAL; date: DATE] y puede usar como una forma simple de descripción cuando una clase no es necesaria. Una instancia de una tupla es simplemente una secuencia de valores entre parentesis ● ["Brigitte", 3.5, Anoche] 41 3.8 Tuplas ● ● Los componentes de una tupla pueden accederse como si fueran atributos de una clase, por ejemplo si t ha sido asignado a la tupla, t.peso sería 3.5 La notación del punto también puede usarse para asignar valores a una tupla t.peso := t.peso + 0.5 ● Los nombres de atributos son opcionales, por tanto, puede expresarse una tupla como TUPLE [A, B, C]. 42 3.9 Bloques (agent) ● Pueden ser utilizados para realizar iteraciones Una_lista.do_all (agent acción) Si queremos ejecutar las acciones solo para los elementos que cumplen una condición ● Una_lista.do_if (agent acción, agent condición) 43 3.9 Bloques (agent) En los ejemplos anteriores, acción y condición son rutinas. Al poner la palabra agent delante se llama automáticamente con los parámetros adecuados. ● Si deseamos llamar a una rutina cualquiera, podemos hacerlo de 2 formas ● ● a.call([args]) siendo a una rutina ● Directamente a ([args]) Los argumentos se pasan como una tupla ● 44 3.10 Métodos “una sola vez” (once routines) Estos métodos realizan los cálculos una sola vez (en la primera llamada), y las demás veces que se invocan devuelven una referencia al resultado. ● Para declarar estos métodos utilizaremos la palabra once en lugar de do. ● shared_object: SOME_TYPE once create Result.make (args) -- This creates the object and returns a reference to it through Result end 45 3.11 Conversiones Eiffel proporciona, al igual que otros muchos lenguajes, mecanismos de conversión. ● Simplemente generaliza los mecanismos de conversión de la mayoría de los lenguajes de programación, pudiéndose aplicar siempre que los tipos sean compatibles. ● 46 3.11 Conversiones ● Se puede realizar: my_string := my_date Convierte una fecha en un string. create my_string.make_from_date (my_date) Para realizar la conversión de la primera forma, es necesario que haya un constructor implementado para dicho fin, es decir, haber implementado la segunda forma ● 47 3.12 Manejo de excepciones ● Se realiza a nivel de procedimientos. Si una operación falla en una rutina, la rutina entera falla y se produce un error. ● Si dicho error no lo maneja dicha rutina es transferido a la rutina superior, así sucesivamente hasta que, o bien se captura la excepción, o llega el error al SO. ● 48 3.12 Manejo de excepciones Para capturar las excepciones se utilizan los bloques rescue. Éstos se ejecutan cuando se produce un fallo. Son similares a los bloques try–catch de Java. ● Se puede volver a probar a ejecutar la rutina que falló después de realizar las operaciones de gestión del error usando la palabra retry dentro del código del bloque rescue (esto no existe en Java). ● 49 3.13 Concurrencia Existen bibliotecas de hebras como EiffelThreads y otras muchas, pero que aún no forman parte de la espcificación estándar oficial de Eiffel. ● 50 3.14 Operadores La interpretación de una operación del tipo a+b es a.plus(b). ● Para implementar un alias para una función se hace lo siguiente: ● <func> alias “<op>” (<param>:<tipo>):<tipo_devuleto> ---declaración normal de función--end 51 3.14 Operadores Existen también operadores libres que se pueden utilizar para definir sintaxis infija o prefija, por ejemplo para aplicaciones matemáticas o fijas. ● Cada clase puede tener, además, una función asociada con el operador ‘[]’ para poder utilizar la notación a[i] en las clases que tengan estructura similar a un array (vectores, matrices, …). ● 52 3.15 Léxico y sintaxis Eiffel no es sensible a las mayúsculas ● Los comentarios de linea se indican con - - ● El separador de instrucciones (;) se suele omitir, salvo para separar instrucciones en la misma línea ● Es usual agrupar los métodos con características similares para una mayor legibilidad ● class <nombre> inherit <clases> feature --declaraciones ... end 53 3.15 Interfaces para otras herramientas y lenguajes Eiffel, a pesar de ser un L.O.O., posee una arquitectura abierta para interaccionar con software externo. ● Proporciona un interfaz directo con C/C++. La mayoría de los compiladores de Eiffel utilizan C como lenguaje intermedio. ● Las últimas versiones del compilador SmartEiffel ofrcen también la posibilidad de generar bytecode de Java 54 ●