stringtranslate.com

Eiffel (lenguaje de programación)

Eiffel es un lenguaje de programación orientado a objetos diseñado por Bertrand Meyer (un defensor de la orientación a objetos y autor de Object-Oriented Software Construction ) y Eiffel Software. Meyer concibió el lenguaje en 1985 con el objetivo de aumentar la confiabilidad del desarrollo de software comercial; [4] la primera versión estuvo disponible en 1986. En 2005, Eiffel se convirtió en un lenguaje estandarizado ISO .

El diseño del lenguaje está estrechamente relacionado con el método de programación Eiffel. Ambos se basan en un conjunto de principios, que incluyen el diseño por contrato , la separación comando-consulta , el principio de acceso uniforme , el principio de elección única , el principio abierto-cerrado y la separación opción-operando .

Muchos conceptos inicialmente introducidos por Eiffel llegaron más tarde a Java , C# y otros lenguajes. [5] Nuevas ideas de diseño de lenguaje, particularmente a través del proceso de estandarización Ecma / ISO , continúan incorporándose al lenguaje Eiffel.

Características

Las características clave del lenguaje Eiffel incluyen:

Objetivos de diseño

Eiffel enfatiza las declaraciones declarativas sobre el código procesal e intenta eliminar la necesidad de instrucciones contables.

Eiffel evita trucos de codificación o técnicas de codificación que pretenden ser sugerencias de optimización para el compilador. El objetivo no es sólo hacer que el código sea más legible, sino también permitir a los programadores concentrarse en los aspectos importantes de un programa sin atascarse en los detalles de implementación. La simplicidad de Eiffel tiene como objetivo promover respuestas simples, extensibles, reutilizables y confiables a los problemas informáticos. Los compiladores de programas informáticos escritos en Eiffel proporcionan amplias técnicas de optimización, como la inserción automática, que alivian al programador de parte de la carga de optimización.

Fondo

Eiffel fue desarrollado originalmente por Eiffel Software, una empresa fundada por Bertrand Meyer . La construcción de software orientada a objetos contiene un tratamiento detallado de los conceptos y la teoría de la tecnología de objetos que llevaron al diseño de Eiffel. [9]

El objetivo de diseño detrás del lenguaje, las bibliotecas y los métodos de programación de Eiffel es permitir a los programadores crear módulos de software confiables y reutilizables. Eiffel admite herencia múltiple , genericidad , polimorfismo , encapsulación , conversiones de tipo seguro y covarianza de parámetros . La contribución más importante de Eiffel a la ingeniería de software es el diseño por contrato (DbC), en el que se emplean aserciones , condiciones previas , condiciones posteriores e invariantes de clase para ayudar a garantizar la corrección del programa sin sacrificar la eficiencia.

El diseño de Eiffel se basa en la teoría de la programación orientada a objetos, con sólo una pequeña influencia de otros paradigmas o preocupación por el soporte del código heredado. Eiffel admite formalmente tipos de datos abstractos . Según el diseño de Eiffel, un texto de software debería poder reproducir su documentación de diseño a partir del texto mismo, utilizando una implementación formalizada del "Tipo de datos abstractos".

Implementaciones y entornos.

EiffelStudio es un entorno de desarrollo integrado disponible bajo licencia comercial o de código abierto . Ofrece un entorno orientado a objetos para la ingeniería de software . EiffelEnvision es un complemento para Microsoft Visual Studio que permite a los usuarios editar, compilar y depurar proyectos Eiffel desde el IDE de Microsoft Visual Studio. Hay otras cinco implementaciones de código abierto disponibles: tecomp "The Eiffel Compiler"; Gobo Eiffel; SmartEiffel , la implementación de GNU, basada en una versión anterior del lenguaje; LibertyEiffel , basado en el compilador SmartEiffel; y Visual Eiffel .

Varios otros lenguajes de programación incorporan elementos introducidos por primera vez en Eiffel. Sather , por ejemplo, se basó originalmente en Eiffel, pero desde entonces se ha diversificado y ahora incluye varias características de programación funcional . El lenguaje de enseñanza interactiva Blue, precursor de BlueJ , también tiene su sede en Eiffel. Apple Media Tool incluye un Apple Media Language basado en Eiffel.

Especificaciones y estándares

La definición del lenguaje Eiffel es un estándar internacional de la ISO . El estándar fue desarrollado por ECMA International , que aprobó el estándar por primera vez el 21 de junio de 2005 como Estándar ECMA-367, Eiffel: Análisis, Diseño y Lenguaje de Programación. En junio de 2006, ECMA e ISO adoptaron la segunda versión. En noviembre de 2006, ISO publicó por primera vez esa versión. El estándar se puede encontrar y utilizar de forma gratuita en el sitio de ECMA. [10] La versión ISO [11] es idéntica en todos los aspectos excepto en el formato.

Eiffel Software, tecomp "The Eiffel Compiler" y Gobo, desarrollador de la biblioteca Eiffel, se han comprometido a implementar el estándar; EiffelStudio 6.1 de Eiffel Software y el tecomp "The Eiffel Compiler" implementan algunos de los principales mecanismos nuevos, en particular, agentes en línea, comandos de asignadores, notación entre corchetes, herencia no conforme y tipos adjuntos. El equipo de SmartEiffel se ha alejado de este estándar para crear su propia versión del lenguaje, que creen que se acerca más al estilo original de Eiffel. Object Tools no ha revelado si las versiones futuras de su compilador Eiffel cumplirán con el estándar. LibertyEiffel implementa un dialecto entre el lenguaje SmartEiffel y el estándar.

La norma cita las siguientes especificaciones predecesoras del lenguaje Eiffel:

La versión actual del estándar de junio de 2006 contiene algunas inconsistencias (por ejemplo, redefiniciones covariantes) [ cita necesaria ] . El comité ECMA aún no ha anunciado ningún cronograma ni dirección sobre cómo resolver las inconsistencias.

Sintaxis y semántica

Estructura general

Un "sistema" o "programa" Eiffel es una colección de clases . Por encima del nivel de clases, Eiffel define cluster , que es esencialmente un grupo de clases y posiblemente de subclusters (clusters anidados). Los grupos no son una construcción del lenguaje sintáctico , sino más bien una convención organizativa estándar. Normalmente, un programa Eiffel se organizará con cada clase en un archivo separado y cada grupo en un directorio que contiene archivos de clase. En esta organización, los subclústeres son subdirectorios. Por ejemplo, según las convenciones estándar de organización y mayúsculas, x.epodría ser el nombre de un archivo que define una clase llamada X.

Una clase contiene características que son similares a "rutinas", "miembros", "atributos" o "métodos" en otros lenguajes de programación orientados a objetos. Una clase también define sus invariantes y contiene otras propiedades, como una sección de "notas" para documentación y metadatos. Los tipos de datos estándar de Eiffel, como y INTEGER, son en sí mismos clases.STRINGARRAY

Cada sistema debe tener una clase designada como "raíz", con uno de sus procedimientos de creación designado como "procedimiento raíz". Ejecutar un sistema consiste en crear una instancia de la clase raíz y ejecutar su procedimiento raíz. Generalmente, al hacerlo se crean nuevos objetos, se invocan nuevas funciones, etc.

Eiffel tiene cinco instrucciones ejecutables básicas: asignación, creación de objetos, llamada a rutina, condición e iteración. Las estructuras de control de Eiffel son estrictas a la hora de hacer cumplir la programación estructurada : cada bloque tiene exactamente una entrada y exactamente una salida.

Alcance

A diferencia de muchos lenguajes orientados a objetos, pero al igual que Smalltalk , Eiffel no permite ninguna asignación a atributos de objetos, excepto dentro de las características de un objeto, que es la aplicación práctica del principio de ocultación de información o abstracción de datos, que requiere interfaces formales para los datos. mutación. Para ponerlo en el lenguaje de otros lenguajes de programación orientados a objetos, todos los atributos de Eiffel están "protegidos" y se necesitan "definidores" para que los objetos del cliente modifiquen los valores. Un resultado de esto es que los "definidores" pueden implementar, y normalmente lo hacen, las invariantes para las cuales Eiffel proporciona sintaxis.

Si bien Eiffel no permite el acceso directo a las características de una clase por parte de un cliente de la clase, sí permite la definición de un "comando de asignador", como por ejemplo:

  some_attribute : SOME_TYPE asignar set_some_attribute set_some_attribute ( v : VALUE_TYPE ) - Establece el valor de some_attribute en `v'. hacer algún_atributo : = v final             

Si bien es una ligera reverencia a la comunidad de desarrolladores en general para permitir algo que parezca un acceso directo (por ejemplo, rompiendo así el principio de ocultación de información), la práctica es peligrosa ya que oculta u ofusca la realidad de que se está utilizando un "configurador". En la práctica, es mejor redirigir la llamada a un configurador en lugar de implicar un acceso directo a una función como some_attributeen el código de ejemplo anterior. [ cita necesaria ]

A diferencia de otros lenguajes, que tienen nociones de "público", "protegido", "privado", etc., Eiffel utiliza una tecnología de exportación para controlar con mayor precisión el alcance entre las clases de clientes y proveedores. La visibilidad de las funciones se verifica estáticamente en tiempo de compilación. Por ejemplo, (a continuación), "{NONE}" es similar a "protegido" en otros idiomas. El alcance aplicado de esta manera a un "conjunto de características" (por ejemplo, todo lo que está debajo de la palabra clave 'característica' hasta la siguiente palabra clave del conjunto de características o el final de la clase) se puede cambiar en clases descendientes usando la palabra clave "exportar".

característica { NONE } - Inicialización default_create - Inicializa una nueva instancia decimal "cero". hacer make_zero final  

Alternativamente, la falta de una declaración de exportación {x} implica {ANY} y es similar al alcance "público" de otros idiomas.

característica - Constantes 

Finalmente, el alcance se puede controlar de manera selectiva y precisa para cualquier clase en el universo del proyecto Eiffel, como por ejemplo:

característica { DECIMAL , DCM_MA_DECIMAL_PARSER , DCM_MA_DECIMAL_HANDLER } - Acceso    

Aquí, el compilador permitirá que solo las clases enumeradas entre llaves accedan a las funciones dentro del grupo de funciones (por ejemplo, DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER ).

"¡Hola Mundo!"

La apariencia de un lenguaje de programación a menudo se transmite mediante un "¡Hola, mundo!" programa. Un programa escrito en Eiffel podría ser:

clase HELLO_WORLD crear hacer característica hacer imprimir ( "¡ Hola , mundo!%N" ) fin fin       

Este programa contiene la clase HELLO_WORLD. El constructor (crear rutina) para la clase, llamado make, invoca la printrutina de la biblioteca del sistema para escribir un "Hello, world!"mensaje en la salida.

Diseño por contrato

El concepto de Diseño por Contrato es central para Eiffel. Los contratos afirman lo que debe ser cierto antes de que se ejecute una rutina (condición previa) y lo que debe ser verdadero después de que finalice la rutina (condición posterior). Los contratos de clase invariante definen qué afirmaciones deben ser verdaderas antes y después de que se acceda a cualquier característica de una clase (tanto rutinas como atributos). Además, los contratos codifican en código ejecutable las suposiciones de los desarrolladores y diseñadores sobre el entorno operativo de las características de una clase o de la clase en su conjunto mediante el invariante.

El compilador Eiffel está diseñado para incluir contratos de características y clases en varios niveles. EiffelStudio, por ejemplo, ejecuta todos los contratos de características y clases durante la ejecución en el "modo Workbench". Cuando se crea un ejecutable, el compilador recibe instrucciones a través del archivo de configuración del proyecto (por ejemplo, archivo ECF) para incluir o excluir cualquier conjunto de contratos. Por lo tanto, se puede compilar un archivo ejecutable para incluir o excluir cualquier nivel de contrato, aportando así niveles continuos de pruebas unitarias y de integración. Además, los contratos se pueden ejercer de forma continua y metódica mediante la función de prueba automática que se encuentra en EiffelStudio.

Los mecanismos de Diseño por contrato están estrechamente integrados con el lenguaje y guían la redefinición de características en herencia:

Además, el lenguaje admite una "instrucción de verificación" (una especie de "afirmación"), invariantes de bucle y variantes de bucle (que garantizan la terminación del bucle).

Capacidad a prueba de vacíos

La capacidad de protección contra vacíos, como la escritura estática, es otra posibilidad para mejorar la calidad del software. El software a prueba de anulación está protegido contra errores de tiempo de ejecución causados ​​por llamadas para anular referencias y, por lo tanto, será más confiable que el software en el que pueden ocurrir llamadas para anular objetivos. La analogía con la escritura estática es útil. De hecho, la capacidad de seguridad contra vacíos podría verse como una extensión del sistema tipográfico, o un paso más allá de la tipificación estática, porque el mecanismo para garantizar la seguridad contra vacíos está integrado en el sistema tipográfico.

La protección contra las llamadas de objetivos vacíos puede verse a través de la noción de apego y (por extensión) desapego (por ejemplo, palabra clave desmontable). La función de seguridad contra vacíos se puede ver en una breve revisión del código de ejemplo usado anteriormente:

 some_attribute : desmontable SOME_TYPE use_some_attribute - Establece el valor de some_attribute en `v'. hacer si se adjunta algún_atributo como l_attribute entonces hacer_algo ( l_attribute ) end end hacer_algo ( a_value : SOME_TYPE ) - Hacer algo con `a_value'. hacer ... haciendo algo con ` a_value ' ... fin                             

El ejemplo de código anterior muestra cómo el compilador puede abordar estáticamente la confiabilidad de si some_attributese adjuntará o desconectará en el punto en que se usa. En particular, la attachedpalabra clave permite un "adjunto local" (p. ej. l_attribute), que tiene como alcance únicamente el bloque de código encerrado por la construcción de declaración if. Por lo tanto, dentro de este pequeño bloque de código, l_attributese puede garantizar estáticamente que la variable local (por ejemplo, ) no será nula (es decir, segura para nulos).

Características: comandos y consultas.

La característica principal de una clase es que define un conjunto de características: como una clase representa un conjunto de objetos en tiempo de ejecución, o "instancias", una característica es una operación sobre estos objetos. Hay dos tipos de funciones: consultas y comandos. Una consulta proporciona información sobre una instancia. Un comando modifica una instancia.

La distinción comando-consulta es importante para el método Eiffel. En particular:

Sobrecarga

Eiffel no permite la sobrecarga de argumentos . Cada nombre de característica dentro de una clase siempre se asigna a una característica específica dentro de la clase. Un nombre, dentro de una clase, significa una cosa. Esta elección de diseño ayuda a la legibilidad de las clases, al evitar una causa de ambigüedad sobre qué rutina será invocada por una llamada. También simplifica el mecanismo del lenguaje; en particular, esto es lo que hace posible el mecanismo de herencia múltiple de Eiffel. [12]

Por supuesto, los nombres se pueden reutilizar en diferentes clases. Por ejemplo, la característica plus (junto con su alias infijo "+" ) se define en varias clases: INTEGER , REAL , STRING , etc.

Genericidad

Una clase genérica es una clase que varía según el tipo (por ejemplo, LISTA [TELÉFONO], una lista de números de teléfono; CUENTA [G->TIPO_CUENTA], que permite CUENTA [AHORROS] y CUENTA [CHEQUES], etc.). Las clases pueden ser genéricas, para expresar que están parametrizadas por tipos. Los parámetros genéricos aparecen entre corchetes:

clase LISTA [ G ] ...   

G se conoce como "parámetro genérico formal". (Eiffel reserva "argumento" para rutinas y usa "parámetro" sólo para clases genéricas). Con tal declaración, G representa dentro de la clase un tipo arbitrario; entonces una función puede devolver un valor de tipo G, y una rutina puede tomar un argumento de ese tipo:

elemento : G hacer ... fin poner ( x : G ) hacer ... fin         

Los LIST [INTEGER]y LIST [WORD]son "derivaciones genéricas" de esta clase. Las combinaciones permitidas (con n: INTEGER, w: WORD, il: LIST [INTEGER], wl: LIST [WORD]) son:

n := il . artículo wl . poner ( w )   

INTEGERy WORDson los "parámetros genéricos reales" en estas derivaciones genéricas.

También es posible tener parámetros formales 'restringidos', para los cuales el parámetro real debe heredar de una clase determinada, la "restricción". Por ejemplo, en

 clase HASH_TABLE [ G , LLAVE -> HASHABLE ]     

una derivación HASH_TABLE [INTEGER, STRING]es válida sólo si STRINGse hereda de HASHABLE(como ocurre en las bibliotecas típicas de Eiffel). Dentro de la clase, habiendo KEYrestringido por HASHABLEmedio de que x: KEYes posible aplicar a xtodas las características de HASHABLE, como en x.hash_code.

Conceptos básicos de herencia

Para heredar de una o más otras, una clase incluirá una inheritcláusula al principio:

clase C hereda A B    -- ... Resto de declaración de clase ...

La clase puede redefinir (anular) algunas o todas las características heredadas. Esto debe anunciarse explícitamente al comienzo de la clase a través de una redefinesubcláusula de la cláusula de herencia, como en

clase C heredar A redefinir f , g , h end B redefinir u , v end             

Véase [13] para una discusión completa sobre la herencia Eiffel.

Clases y funciones diferidas

Las clases se pueden definir con deferred classen lugar de con classpara indicar que no se puede crear una instancia directa de la clase. Las clases no instanciables se denominan clases abstractas en algunos otros lenguajes de programación orientados a objetos. En el lenguaje de Eiffel, sólo se puede instanciar una clase "efectiva" (puede ser descendiente de una clase diferida). Una característica también se puede aplazar utilizando la deferredpalabra clave en lugar de una docláusula. Si una clase tiene alguna característica diferida debe declararse como diferida; sin embargo, una clase sin características diferidas puede, no obstante, ser diferida.

Las clases diferidas desempeñan aproximadamente el mismo papel que las interfaces en lenguajes como Java, aunque muchos teóricos de la programación orientada a objetos creen que las interfaces en sí mismas son en gran medida una respuesta a la falta de herencia múltiple de Java (que tiene Eiffel). [14] [15]

Cambiar el nombre

Una clase que hereda de una o más otras obtiene todas sus características, de forma predeterminada, con sus nombres originales. Podrá, sin embargo, cambiar sus denominaciones mediante renamecláusulas. Esto es necesario en el caso de herencia múltiple si hay conflictos de nombres entre características heredadas; sin cambiar el nombre, la clase resultante violaría el principio de no sobrecarga mencionado anteriormente y, por lo tanto, no sería válida.

tuplas

Los tipos de tuplas pueden verse como una forma simple de clase, que proporciona sólo atributos y el correspondiente procedimiento "establecedor". Un tipo de tupla típico lee

 TUPLE [ nombre : STRING ; peso : REAL ; fecha : FECHA ]      

y podría usarse para describir una noción simple de acta de nacimiento si no se necesita una clase. Una instancia de dicha tupla es simplemente una secuencia de valores con los tipos dados, entre paréntesis, como

 [ "Brigitte" , 3.5 , Anoche ]  

Se puede acceder a los componentes de dicha tupla como si las etiquetas de la tupla fueran atributos de una clase; por ejemplo, si se le tha asignado la tupla anterior, entonces t.weighttiene el valor 3,5.

Gracias a la noción de comando de asignación (ver más abajo), la notación de puntos también se puede utilizar para asignar componentes de dicha tupla, como en

 t . peso := t . peso + 0,5    

Las etiquetas de tupla son opcionales, por lo que también es posible escribir un tipo de tupla como TUPLE [STRING, REAL, DATE]. (En algunos compiladores esta es la única forma de tupla, ya que las etiquetas se introdujeron con el estándar ECMA).

La especificación precisa de eg TUPLE [A, B, C]es que describe secuencias de al menos tres elementos, siendo los tres primeros de tipo A, B, Crespectivamente. Como resultado, TUPLE [A, B, C]se ajusta a (se puede asignar a) TUPLE [A, B], a TUPLE [A]y a TUPLE(sin parámetros), el tipo de tupla superior al que se ajustan todos los tipos de tupla.

Agentes

El mecanismo de "agente" de Eiffel envuelve las operaciones en objetos. Este mecanismo se puede utilizar para iteración, programación basada en eventos y otros contextos en los que sea útil pasar operaciones alrededor de la estructura del programa. Otros lenguajes de programación, especialmente aquellos que enfatizan la programación funcional , permiten un patrón similar usando continuaciones , cierres o generadores ; Los agentes de Eiffel enfatizan el paradigma orientado a objetos del lenguaje y usan una sintaxis y semántica similar a los bloques de código en Smalltalk y Ruby .

Por ejemplo, para ejecutar el my_actionbloque para cada elemento de my_list, se escribiría:

 mi lista . do_all ( agente mi_acción )  

Para ejecutar my_actionsolo en elementos que cumplan my_condition, se puede agregar una limitación/filtro:

 mi lista . do_if ( agente mi_acción , agente mi_condición )    

En estos ejemplos, my_actiony my_conditionson rutinas. Al anteponerlos agentse obtiene un objeto que representa la rutina correspondiente con todas sus propiedades, en particular la capacidad de ser llamado con los argumentos apropiados. Entonces, si arepresenta ese objeto (por ejemplo, porque aes el argumento de do_all), la instrucción

 a . llamar ( [ x ] ) 

llamará a la rutina original con el argumento x, como si hubiésemos llamado directamente a la rutina original: my_action (x). Los argumentos se callpasan como una tupla, aquí [x].

Es posible mantener abiertos algunos argumentos para un agente y cerrar otros . Los argumentos abiertos se pasan como argumentos a call: se proporcionan en el momento del uso del agente . Los argumentos cerrados se proporcionan en el momento de la definición del agente . Por ejemplo, si action2tiene dos argumentos, la iteración

 mi lista . do_all ( agente acción2 ( ? , y ))    

itera action2 (x, y)para valores sucesivos de x, donde el segundo argumento permanece establecido en y. El signo de interrogación ?indica un argumento abierto; yes un argumento cerrado del agente. Tenga en cuenta que la sintaxis básica agent fes una abreviatura de agent f (?, ?, ...)con todos los argumentos abiertos. También es posible hacer que el objetivo de un agente se abra mediante la notación {T}?donde Testá el tipo de objetivo.

La distinción entre operandos abiertos y cerrados (operandos = argumentos + objetivo) corresponde a la distinción entre variables ligadas y libres en el cálculo lambda . Una expresión de agente, como por ejemplo action2 (?, y)con algunos operandos cerrados y otros abiertos, corresponde a una versión de la operación original aplicada a los operandos cerrados.

El mecanismo del agente también permite definir un agente sin referencia a una rutina existente (como my_action, my_condition, action2), a través de agentes en línea como en

mi lista . do_all ( agente ( s : STRING ) requiere not_void : s /= Void do s . append_character ( ',' ) asegúrese de agregar : s . count = old s . count + 1 end )                    

El agente en línea pasado aquí puede tener todos los elementos de una rutina normal, incluidas condiciones previas, condiciones posteriores, cláusula de rescate (no utilizada aquí) y una firma completa. Esto evita definir rutinas cuando todo lo que se necesita es un cálculo que se incluirá en un agente. Esto es útil en particular para contratos, como en una cláusula invariante que expresa que todos los elementos de una lista son positivos:

 mi lista . for_all ( agente ( x : INTEGER ): BOOLEAN do Resultado : = ( x > 0 ) end )           

El mecanismo del agente actual deja una posibilidad de error de tipo en tiempo de ejecución (si se pasa una rutina con n argumentos a un agente que espera m argumentos con m < n ). Esto se puede evitar mediante una verificación en tiempo de ejecución mediante la condición previa valid_argumentsde call. Se encuentran disponibles varias propuestas para una corrección puramente estática de este problema, incluida una propuesta de cambio de idioma de Ribet et al. [dieciséis]

Una vez rutinas

El resultado de una rutina se puede almacenar en caché utilizando la oncepalabra clave en lugar de do. Las llamadas que no son las primeras a una rutina no requieren ningún cálculo adicional ni asignación de recursos, sino que simplemente devuelven un resultado calculado previamente. Un patrón común para las "funciones únicas" es proporcionar objetos compartidos; la primera llamada creará el objeto, las siguientes devolverán la referencia a ese objeto. El esquema típico es:

objeto_compartido : SOME_TYPE una vez creado el resultado . make ( args ) : esto crea el objeto y devuelve una referencia a él a través de "Resultado". fin       

El objeto devuelto ( Resulten el ejemplo) puede ser mutable, pero su referencia sigue siendo la misma.

A menudo, las "rutinas únicas" realizan una inicialización requerida: varias llamadas a una biblioteca pueden incluir una llamada al procedimiento de inicialización, pero solo la primera llamada realizará las acciones requeridas. Con este patrón, la inicialización se puede descentralizar, evitando la necesidad de un módulo de inicialización especial. Las "rutinas Once" son similares en propósito y efecto al patrón singleton en muchos lenguajes de programación y al patrón Borg utilizado en Python.

De forma predeterminada, una "rutina única" se llama una vez por subproceso . La semántica se puede ajustar a una vez por proceso o una vez por objeto calificándola con una "clave única", por ejemplo once ("PROCESS").

Conversiones

Eiffel proporciona un mecanismo para permitir conversiones entre varios tipos. El mecanismo coexiste con la herencia y la complementa. Para evitar cualquier confusión entre los dos mecanismos, el diseño aplica el siguiente principio:

(Principio de conversión) Un tipo no puede ajustarse ni convertirse en otro.

Por ejemplo, NEWSPAPERpuede ajustarse a PUBLICATION, pero INTEGERse convierte a REAL(y no hereda de él).

El mecanismo de conversión simplemente generaliza las reglas de conversión ad hoc (como entre INTEGERy REAL) que existen en la mayoría de los lenguajes de programación, haciéndolas aplicables a cualquier tipo siempre que se respete el principio anterior. Por ejemplo, DATEse puede declarar una clase para convertirla en STRING; esto hace posible crear una cadena a partir de una fecha simplemente a través de

 mi_cadena := mi_fecha  

como un atajo para usar una creación explícita de objetos con un procedimiento de conversión:

 crear mi_cadena . make_from_date ( mi_fecha )  

Para que la primera forma sea posible como sinónimo de la segunda, basta con enumerar el procedimiento de creación (constructor) make_from_dateen una convertcláusula al comienzo de la clase.

Como otro ejemplo, si existe un procedimiento de conversión de este tipo en la lista TUPLE [day: INTEGER; month: STRING; year: INTEGER], entonces se puede asignar directamente una tupla a una fecha, provocando la conversión adecuada, como en

 Día_de la Bastilla := [ 14 , "julio" , 1789 ]    

Manejo de excepciones

El manejo de excepciones en Eiffel se basa en los principios del diseño por contrato. Por ejemplo, se produce una excepción cuando el llamador de una rutina no cumple una condición previa o cuando una rutina no puede garantizar una condición posterior prometida. En Eiffel, el manejo de excepciones no se utiliza para controlar el flujo ni para corregir errores en la entrada de datos.

Un controlador de excepciones Eiffel se define utilizando la palabra clave de rescate . Dentro de la sección de rescate , la palabra clave reintentar ejecuta la rutina nuevamente. Por ejemplo, la siguiente rutina rastrea la cantidad de intentos de ejecutar la rutina y solo reintenta una cierta cantidad de veces:

connect_to_server ( servidor : SOCKET ) : conéctese a un servidor o abandone después de 10 intentos. require server /= Void y luego server . dirección /= Intentos locales nulos : INTEGER do server . conectar asegúrese de estar conectado : servidor . rescate is_connected si intentos < 10 entonces intentos : = intentos + 1 reintento fin fin                                  

Sin embargo, se puede decir que este ejemplo es defectuoso para cualquier cosa que no sean los programas más simples, porque es de esperar que se produzcan fallos en la conexión. Para la mayoría de los programas, un nombre de rutina como intento_conexión_al_servidor sería mejor, y la poscondición no prometería una conexión, dejando a la persona que llama tomar las medidas apropiadas si la conexión no se abre.

concurrencia

Se encuentran disponibles varias bibliotecas de redes y subprocesos, como EiffelNet y EiffelThreads. Un modelo de concurrencia para Eiffel, basado en los conceptos de diseño por contrato, es SCOOP , o Programación Orientada a Objetos Concurrente Simple , que aún no forma parte de la definición del lenguaje oficial pero está disponible en EiffelStudio . CAMEO [17] es una variación (no implementada) de SCOOP para Eiffel. La concurrencia también interactúa con las excepciones. Las excepciones asincrónicas pueden ser problemáticas (donde una rutina genera una excepción después de que el autor de la llamada haya terminado). [18]

Sintaxis de operadores y corchetes, comandos de asignador

La visión de Eiffel sobre la computación está completamente orientada a objetos en el sentido de que cada operación es relativa a un objeto, el "objetivo". Así, por ejemplo, una adición como

a + b  

se entiende conceptualmente como si fuera la llamada al método

a . más ( segundo ) 

con objetivo a, característica plusy argumento b.

Por supuesto, la primera es la sintaxis convencional y normalmente se prefiere. La sintaxis del operador permite utilizar cualquiera de las formas declarando la característica (por ejemplo en INTEGER, pero esto se aplica a otras clases básicas y se puede utilizar en cualquier otra para la que dicho operador sea apropiado):

más alias "+" ( otro : INTEGER ): INTEGER -- ... Declaración de función normal... fin       

La gama de operadores que se pueden utilizar como "alias" es bastante amplia; incluyen operadores predefinidos como "+", pero también "operadores libres" compuestos de símbolos no alfanuméricos. Esto hace posible diseñar notaciones especiales de infijos y prefijos, por ejemplo en aplicaciones de matemáticas y física.

Cada clase puede tener además una función con el alias "[]", el operador "corchete", permitiendo la notación a [i, ...]como sinónimo de a.f (i, ...)dónde festá la función elegida. Esto es particularmente útil para estructuras de contenedores como matrices, tablas hash , listas, etc. Por ejemplo, se puede escribir el acceso a un elemento de una tabla hash con claves de cadena.

 número := directorio telefónico [ "JILL SMITH" ]   

Los "comandos del asignador" son un mecanismo complementario diseñado con el mismo espíritu de permitir una notación conveniente y bien establecida reinterpretada en el marco de la programación orientada a objetos. Los comandos del asignador permiten una sintaxis similar a la de una asignación para llamar a procedimientos "establecedores". Una asignación propiamente dicha nunca puede ser de la forma a.x := vya que esto viola el ocultamiento de información; tienes que buscar un comando de establecimiento (procedimiento). Por ejemplo, la clase de tabla hash puede tener la función y el procedimiento

alias del elemento "[]" ( clave : STRING ): ELEMENTO [ 3 ] - El elemento de la clave 'clave'. -- (consulta "Getter") hacer ... finalizar           put ( e : ELEMENT ; key : STRING ) - Inserta el elemento `e', asociándolo con la clave `key'. -- (comando "Setter") hacer ... finalizar         

Luego, para insertar un elemento, debe usar una llamada explícita al comando de configuración:

 [ 4 ] directorio telefónico . poner ( Nueva_persona , "JILL SMITH" )   

Es posible escribir esto de manera equivalente como

 [ 5 ] agenda_telefónica [ "JILL SMITH" ] := Nueva_persona    

(de la misma manera que phone_book ["JILL SMITH"]es sinónimo de number := phone_book.item ("JILL SMITH")), siempre que la declaración de itemnow comience (reemplazo de [3]) con

 alias del elemento "[]" ( clave : CADENA ): ELEMENTO asignar poner       

Esto se declara putcomo el comando del asignador asociado itemy, combinado con el alias del corchete, hace que [5] sea legal y equivalente a [4]. (También se podría escribir, sin aprovechar el corchete, como phone_book.item ("JILL SMITH") := New_person.

Nota: La lista de argumentos del asignador de a está restringida a ser: (el tipo de retorno de a; toda la lista de argumentos de a...)

Propiedades léxicas y sintácticas.

Eiffel no distingue entre mayúsculas y minúsculas. Los tokens makey maKetodos MAKEdenotan el mismo identificador. Consulte, sin embargo, las "reglas de estilo" a continuación.

Los comentarios se introducen con --(dos guiones consecutivos) y se extienden hasta el final de la línea.

El punto y coma, como separador de instrucciones, es opcional. La mayoría de las veces simplemente se omite el punto y coma, excepto para separar varias instrucciones en una línea. Esto da como resultado menos desorden en la página del programa.

No hay anidamiento de declaraciones de características y clases. Como resultado, la estructura de una clase Eiffel es simple: algunas cláusulas a nivel de clase (herencia, invariante) y una sucesión de declaraciones de características, todas al mismo nivel.

Es habitual agrupar características en "cláusulas de características" separadas para una mayor legibilidad, con un conjunto estándar de etiquetas de características básicas que aparecen en un orden estándar, por ejemplo:

clase HASH_TABLE [ ELEMENT , KEY -> HASHABLE ] heredar TABLE [ ELEMENT ]         característica -- Inicialización -- ... Declaraciones de comandos de inicialización (procedimientos de creación/constructores) ...   característica -- Acceso -- ... Declaraciones de consultas no booleanas sobre el estado del objeto, por ejemplo, elemento ...   característica - Informe de estado - ... Declaraciones de consultas booleanas sobre el estado del objeto, por ejemplo, is_empty ...   característica - Cambio de elemento - ... Declaraciones de comandos que cambian la estructura, por ejemplo, poner ...   -- etc. fin

A diferencia de la mayoría de los lenguajes de programación entre llaves , Eiffel hace una clara distinción entre expresiones e instrucciones. Esto está en línea con el principio de separación comando-consulta del método Eiffel.

Convenciones de estilo

Gran parte de la documentación de Eiffel utiliza convenciones de estilo distintivas, diseñadas para imponer una apariencia consistente. Algunas de estas convenciones se aplican al formato del código en sí y otras a la representación tipográfica estándar del código Eiffel en formatos y publicaciones donde estas convenciones son posibles.

Si bien el lenguaje no distingue entre mayúsculas y minúsculas, los estándares de estilo prescriben el uso de mayúsculas para nombres de clases ( LIST), minúsculas para nombres de características ( make) y mayúsculas iniciales para constantes ( Avogadro). El estilo recomendado también sugiere un guión bajo para separar los componentes de un identificador de varias palabras, como en average_temperature.

La especificación de Eiffel incluye pautas para mostrar textos de software en formatos tipográficos: las palabras clave en negrita, los identificadores y constantes definidos por el usuario se muestran en italics, los comentarios, los operadores y los signos de puntuación en Roman, con el texto del programa en bluecomo en el presente artículo para distinguirlo de texto explicativo. Por ejemplo, el mensaje "¡Hola mundo!" El programa proporcionado anteriormente se representaría como se muestra a continuación en la documentación de Eiffel:

clase HELLO_WORLD crear hacer característica hacer imprimir ( "¡ Hola , mundo!" ) fin fin       

Interfaces con otras herramientas y lenguajes

Eiffel es un lenguaje puramente orientado a objetos, pero proporciona una arquitectura abierta para interactuar con software "externo" en cualquier otro lenguaje de programación.

Es posible, por ejemplo, programar operaciones a nivel de máquina y de sistema operativo en C. Eiffel proporciona una interfaz sencilla para las rutinas C, incluido el soporte para "C en línea" (escribir el cuerpo de una rutina Eiffel en C, generalmente para operaciones cortas a nivel de máquina).

Aunque no existe una conexión directa entre Eiffel y C, muchos compiladores de Eiffel ( Visual Eiffel es una excepción) generan código fuente de C como lenguaje intermedio , para enviarlo a un compilador de C, para su optimización y portabilidad . Como tales, son ejemplos de transcompiladores . El compilador Eiffel tecomp puede ejecutar código Eiffel directamente (como un intérprete) sin pasar por un código C intermedio o emitir código C que se pasará a un compilador C para obtener código nativo optimizado. En .NET, el compilador EiffelStudio genera directamente código CIL (Lenguaje Intermedio Común). El compilador SmartEiffel también puede generar código de bytes de Java .

Referencias

  1. ^ "Eiffel en pocas palabras". archivo.eiffel.com . Consultado el 24 de agosto de 2017 .
  2. ^ "¡EiffelStudio 23.09 está disponible!". Eiffel.org . 25 de octubre de 2023.
  3. ^ Cooper, Peter (2009). Ruby principiante: de principiante a profesional . Desde principiante hasta profesional (2ª ed.). Berkeley: Prensa. pag. 101.ISBN 978-1-4302-2363-4. En menor medida, Python, LISP, Eiffel, Ada y C++ también han influido en Ruby.
  4. ^ "Eiffel: el idioma". berenddeboer.net . Consultado el 6 de julio de 2016 .
  5. ^ Meyer, Bertrand (28 de agosto de 2009). Touch of Class: aprender a programar bien con objetos y contratos. Medios de ciencia y negocios de Springer. ISBN 978-3-540-92144-8.
  6. ^ "Lenguajes de programación - Eiffel" (PDF) . Departamento de Ciencias de la Computación, Virginia Tech . Consultado el 25 de marzo de 2023 .
  7. ^ Carl Friess. "Guía de sintaxis Eiffel". Guía de sintaxis de Eiffel . Consultado el 25 de marzo de 2023 .
  8. ^ Claus Brabrand. "El lenguaje de programación EIFFEL" (PDF) . Universidad de TI de Copenhague . Consultado el 25 de marzo de 2023 .
  9. ^ Construcción de software orientada a objetos , segunda edición, por Bertrand Meyer , Prentice Hall, 1997, ISBN 0-13-629155-4 
  10. ^ ECMA International: Estándar ECMA-367 - Eiffel: lenguaje de análisis, diseño y programación, segunda edición (junio de 2006); disponible en línea en www.ecma-international.org/publications/standards/Ecma-367.htm
  11. ^ Organización Internacional de Normalización: Norma ISO/IEC DIS 25436, disponible en línea en [1]
  12. ^ Bertrand Meyer: sobrecarga frente a tecnología de objetos, en Journal of Object-Oriented Programming (JOOP), vol. 14, núm. 4, octubre-noviembre de 2001, disponible en línea
  13. ^ "9 HERENCIA". Archivo.eiffel.com. 1997-03-23 . Consultado el 8 de julio de 2013 .
  14. ^ "Múltiples herencias e interfaces". Artima.com. 2002-12-16 . Consultado el 8 de julio de 2013 .
  15. ^ "La herencia múltiple no es mala". C2.com. 28 de abril de 2007 . Consultado el 8 de julio de 2013 .
  16. ^ Philippe Ribet, Cyril Adrian, Olivier Zendra, Dominique Colnet: Conformidad de agentes en el lenguaje Eiffel , en Journal of Object Technology , vol. 3, núm. 4, abril de 2004, Número especial: TOOLS USA 2003, págs. 125-143. Disponible en línea desde la página del artículo JOT
  17. ^ Brooke, Phillip; Richard Paige (2008). "Cameo: un modelo alternativo de concurrencia para Eiffel" (PDF) . Aspectos formales de la informática . Saltador. 21 (4): 363–391. doi :10.1007/s00165-008-0096-1. S2CID  18336088.
  18. ^ Brooke, Phillip; Richard Paige (2007). "Excepciones en Eiffel concurrente". Revista de tecnología de objetos . 6 (10): 111–126. doi : 10.5381/jot.2007.6.10.a4 .

enlaces externos