Ir al contenido

Eiffel (lenguaje de programación)

De Wikipedia, la enciclopedia libre
Eiffel
Eiffel logo
Desarrollador(es)
Eiffel Software
Información general
Extensiones comunes .e
Paradigma orientado a objetos
Apareció en 1985
Diseñado por Bertrand Meyer
Sistema de tipos fuerte, estático
Implementaciones ISEEiffel, tecomp, SmartEiffel, Visual Eiffel
Influido por Ada, Simula, Z
Ha influido a D, Java, C#, Sather, Ruby
Licencia Dual GPL y enterprise

Eiffel es un lenguaje de programación orientado a objetos que sigue el estándar ISO diseñado por Bertrand Meyer (defensor de los lenguajes orientados a objetos y autor de la construcción de Software Orientado a Objetos) y Software Eiffel. El diseño del lenguaje esta estrechamente relacionado con el método de programación Eiffel. Ambos se basan en una serie de principios incluyendo: el diseño por contrato, la separación de comandos y consultas, el principio de acceso uniforme, el principio de elección única, el principio abierto-cerrado y la separación operación-operando.

Muchos conceptos inicialmente introducidos por Eiffel aparecen más tarde en Java, C# y otros lenguajes. Nuevas ideas de diseño de lenguaje, particularmente a través del proceso de estandarización ECMA/ISO, se continúan incorporando al lenguaje Eiffel.

Características

[editar]

Las características claves del lenguaje Eiffel incluyen:

  • Una estructura de programa orientado a objetos en el que una clase sirve como la unidad básica de la descomposición.
  • Diseño por contrato estrechamente integrado con otras construcciones del lenguaje.
  • Gestión de memoria automática, por lo general implementado por un recolector de basura.
  • Herencia, incluyendo la herencia múltiple, el cambio de nombre, la redefinición, "select", herencia no conforme, y otros mecanismos destinados a hacer que la herencia sea segura.
  • Programación genérica con y sin restricciones.
  • Gestión de un sistema de tipo uniforme donde la semántica del valor y la referencia en el que todos los tipos, incluidos los tipos básicos como entero, son de clase base.
  • Tipado estático
  • Seguridad ausencia de tipos, o protección estática contra las llamadas a referencias a null, a través del mecanismo de tipos de adjuntos.
  • Agentes, o objetos que agrupan a los cálculos, estrechamente relacionados con la clausura y el cálculo lambda
  • Rutinas de ejecución única, o rutinas que se ejecutan solo una vez, para objetos compartidos y la inicialización descentralizada.
  • Sintaxis de palabras clave siguiendo la tradición ALGOL / Pascal pero libre de separadores, en la medida en puntos y comas son opcionales, con la sintaxis disponible para definir operadores para las rutinas.
  • No es sensible a mayúsculas y minúsculas.

Los objetivos de diseño

[editar]

Eiffel destaca enunciados declarativos sobre el código de procedimiento y los intentos de eliminar la necesidad de instrucciones de contabilidad. Eiffel evita trucos o técnicas de codificación destinadas como sugerencias de optimización para el compilador. El objetivo no es sólo para hacer el código más fácil de leer, sino también para permitir a los programadores concentrarse en los aspectos importantes de un programa sin atascarse en los detalles de implementación. La simplicidad de Eiffel está destinada a promover respuestas sencillas, extensibles, reutilizables y fiables a los problemas informáticos. Los compiladores de programas informáticos escritos en Eiffel ofrecen amplias técnicas de optimización, tales como autommatic in-lining, que alivian el programador de parte de la carga, mientras que la optimización de la producción de código cuya eficacia es comparable a la de código escrito en C++ [cita requerida].

Antecedentes

[editar]

Eiffel fue desarrollado originalmente por Eiffel Software, una compañía fundada por Bertrand Meyer. El Software de Construcción Orientado 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.[1]

El objetivo de diseño detrás del lenguaje Eiffel, las librerías y los métodos de programación es permitir a los programadores crear módulos de software fiables y reutilizables. Eiffel soporta herencia múltiple, generalidad, polimorfismo, encapsulación, conversiones de tipo seguro, y covarianza de los parámetros. La contribución más importante de Eiffel de la ingeniería de software es el diseño por contrato (DBC), en el que se emplean las aserciones, precondiciones, postcondiciones y clases invariantes 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 solo un poco influencia de otros paradigmas o algunos conceptos por el soporte de código heredado. Eiffel soporta formalmente los tipos abstractos de datos. En el diseño de Eiffel, un texto de software debe ser capaz de reproducir su documentación de diseño del texto en si, usando una implementación formalizada del tipo de datos abstracto. El lenguaje interactivo de aprendizaje Blue, precursor de BlueJ, también está basado en Eiffel. El Apple Media Tool incluye un Apple Media Lenguaje basado en Eiffel.

Implementaciones y entornos

[editar]

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

Diversos lenguajes de programación incorporan elementos aportados por primera vez en Eiffel. Sather, por ejemplo, se basó originalmente en Eiffel, pero ha variado desde entonces, y ahora incluye características de la programación funcional.

Especificaciones y normas

[editar]

La definición del lenguaje Eiffel es un estándar internacional de la ISO. El estándar fue desarrollado por Ecma International, que por primera vez aprobada la norma, el 21 de junio de 2005, como estándar ECMA 367, Eiffel: Analysis, Design and Implementation Language. En junio de 2006, ECMA e ISO aprobaron la segunda versión. En noviembre de 2006, la ISO publicó por primera vez. El estándar se puede encontrar y utilizar de una manera gratuita en la web de ECMA.[2]​ La versión de ISO[3]​ es idéntica en todos los aspectos salvo en el formato.

Eiffel Software's, "tecomp: The Eiffel Compiler" i Eiffel-library-developer de Gobo se han comprometido a aplicar el estándar; Eiffel Software's EiffelStudio 6.1 and "tecomp: The Eiffel Compiler" implementan algunos de los principales nuevos mecanismos- en particular, los agentes en línea, asignadores de órdenes, notación parenterizada, herencia no conforme, y los tipos anexos. El equipo de SmartEiffel se ha apartado de este estándar para crear su propia versión del lenguaje, que creen que está más cerca del estilo original de Eiffel. Object Tools no ha revelado si en futuras versiones de su compilador de Eiffel cumplirá con el estándar.

El estándar cita los siguientes predecesores de especificaciones del lenguaje Eiffel:

  • Bertrand Meyer: Eiffel: The Language, Prentice Hall, segunda edición, 1992 (Primera edición: 1991)
  • Bertrand Meyer: Standard Eiffel (revisió de l'entrada anterior), en curso, 1997 -presente, a Bertrand Meyer's ETL3 page, i
  • Bertrand Meyer: Object-Oriented Software Construction, Prentice Hall: primera edición, 1988, segunda edición, 1997.

La versión actual del estándar de junio de 2006 contiene algunas inconsistencias (por ejemplo, las redefiniciones de la covarianza). El comité ECMA no ha anunciado ningún calendario ni en que dirección se resolverán estas inconsistencias.

Sintaxis y la semántica

[editar]

Estructura general

[editar]

Un "sistema" o "programa" Eiffel es una colección de clases. Por encima del nivel de clases, Eiffel define el cluster, que es esencialmente un grupo de clases, y posiblemente de subclubsters. Las agrupaciones no son una estructura de control sintáctica, sino más bien una convención de la organización estándar. Normalmente una aplicación Eiffel se organizara con cada clase en un archivo separado, y cada clúster en un directorio o carpeta que contiene los ficheros de las clases. En esta organización, los subclústers son subdirectorios. Por ejemplo, en virtud de las convenciones estándar de la organización y el entorno, x.e podría ser el nombre de un fichero que define una clase llamada X.

Una clase contiene características, que son similares a los "miembros, "atributos" o "métodos" en otros lenguajes de programación orientados a objetos. Una clase también define a sus invarianzas,y contiene otras propiedades, como una sección de "notas" para documentación y metadatos. Los tipos estándar de datos como entero, string o array, son todos ellos clases.

Cada sistema tiene que tener una clase designada como raíz, y uno de sus procedimientos de creación designado como "procedimiento raíz". La ejecución de un sistema consiste en la creación de una instancia de la clase raíz y en ejecutar el procedimiento raíz. En general, eso crea nuevos objetos, llama a nuevas características, y así sucesivamente.

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

Alcance

[editar]

A diferencia de muchos lenguajes orientados a objetos, pero como Smalltalk, Eiffel no permite una asignación en los campos de los objetos, excepto dentro de las características de un objeto. Eiffel hace hincapié en ocultar la información, y la abstracción de datos, en requerir interfaces formales para la mutación de datos. Para expresarlo en el formato de otros lenguajes orientado a objetos, todos los campos Eiffel son privados, y los métodos "set" son necesarios para modificar los valores. Una consecuencia de esto es que el método "set" puede, y normalmente lo hace, implementa las invariancias por los cuales Eiffel proporciona sintaxis.

"Hola Mundo"

[editar]

El primer contacto con un lenguaje de programación se hace a menudo con el uso de un programa "Hola, mundo!". Este programa escrito en Eiffel podría ser:

class
    HOLA_MUNDO
create
    hacer
feature
    hacer
        do
            print ("Hola, mundo!%N")
        end --hacer
end --HOLA_MUNDO

Este programa contiene la clase HOLA_MUNDO. El constructor (rutina creadora) para la clase, de nombre hacer, invoca print que es la rutina de la biblioteca del sistema para escribir un mensaje "Hola, mundo!" al dispositivo de salida.

Diseño por contrato

[editar]

El concepto de diseño por contrato es fundamental para Eiffel. Los mecanismos están estrechamente integrados con el lenguaje. Los contratos guían la redefinición de las características en la herencia.

  • Precondición de la rutina: el único requisito puede ser debilitado por la herencia, cualquier llamada que cumpla con los requisitos del antepasado cumplen con los de los descendientes.
  • Postcondición de la rutina: la postcondición solo puede ser forzada por herencia; ningún resultado garantiza para el antepasado siga en manos de los descendientes.
  • Invariante a clase

Además, el lenguaje soporta una "instrucción de verificación" (una especie de "asserción") y los invariantes de bucle.

Características, órdenes y consultas

[editar]

La propiedad principal de una clase es que contiene un conjunto de características. Como una clase presenta un conjunto de objetos en tiempo de ejecución, o "casos", una característica es un atributo o una operación en estos objetos. Hay dos tipos de funciones: consultas y órdenes. Una consulta proporciona información sobre una instancia. Una orden modifica una instancia.

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

  • Principio de acceso uniforme: desde el punto de vista de un cliente del programa que hace una llamada a una función de clase, si una consulta es un atributo (campo en cada objeto) o una función (algoritmo) no tiene que tener ninguna diferencia. Por ejemplo, a_vehicle.speed podría ser un atributo, que se accede desde la representación del objeto, o puede ser calculado para una función que divide la distancia por el tiempo. La notación es la misma en ambos casos, por lo que es fácil cambiar la representación, sin afectar el resto del programa.
  • Principio de separación orden-consulta: Las consultas no tienen que modificar la instancia. Esto no es una regla del lenguaje, si no un principio metodológico. Así entonces, en buen estilo Eiffel, uno no encuentra un método o función "get" ("getter") que cambie alguna cosa y devuelve un resultado, sino que hay órdenes (procedimientos) para cambiar los objetos, y consultas para obtener información sobre el objeto, como resultado de los cambios anteriores.

Sobrecarga

[editar]

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 opción de diseño ayuda a la legibilidad de las clases, evitando una de las causas de ambigüedad sobre que rutina será invocada con una llamada. También simplifica el mecanismo del lenguaje. En particular, eso es lo que hace posible el mecanismo de la herencia múltiple de Eiffel.[4]

Los nombres pueden, por descontado, son reutilizadas en diferentes clases. Por ejemplo, el operador "+" se define en diversas clases: INTEGER, REAL, STRING, etc.

Genericidad

[editar]

Las clases pueden ser genéricas, para expresar que están parametrizadas para tipos. Los parámetros genéricos aparecen entre corchetes:

class LISTA [G] ...

G se conoce como un "parámetro formal genérico". (Eiffel reserva "argumento" para las rutinas, y utiliza "parámetro" solo para las clases genéricas.) Con esta declaración G representa dentro de la clase un tipo arbitrario, para el que una función puede retornar un valor de tipo G, y una rutina puede tener un argumento de este tipo:

item: G do ... end
pone (x: G) do ... end

La LISTA [INTEGER] y LISTA [WORD] son "derivaciones genéricas" de esta clase. Combinaciones permitas (y con n: INTEGER, w: WORD, il: LISTA [INTEGER], wl: LISTA [WORD]) son:

n := il.item
wl.pone (w)

INTEGER y WORD son los "parámetros genéricos actuales" en estas derivaciones genéricas.

También es posible tener "restricciones" de los parámetros formales, de manera que el parámetro real a de heredar de una clase dada, la "restricción". Por ejemplo, en

   class TABLA_HASH [G, CLAVE -> HASHABLE]

una derivación TABLA_HASH [INTEGER, STRING] es válida únicamente si STRING hereda de HASHABLE (como de hecho hacen las típicas bibliotecas Eiffel). Dentro de la clase, después de haber restringido CLAVE mediante HASHABLE que para x: CLAVE es posible aplicar a x todas las características de HASHABLE, como en x.hash_code.

Fundamentos de la herencia

[editar]

Para heredar de otra o otras, una clase incluirá una cláusula de heredar al principio:

class C inherit
   A
   B

-- ... Resto de la declaración de la clase ...

La clase puede redefinir algunas o todas las características heredadas. Eso ha de ser declarado explícitamente al comienzo de la clase a través de la cláusula redefine subcláusula de la cláusula de herencia, como en:

class C inherit
    A
        redefine f, g, h end
    B
        redefine u, v end

Clases y características diferidas

[editar]

Las clases se pueden definir con deferred class en lugar de con class para indicar que la clase no puede ser instanciada directamente. Las clases no instanciables se dicen clases abstractas en otros lenguajes de programación orientados a objetos. En el lenguaje Eiffel, solo se pueden crear instancias de una clase "efectiva" (que puede ser una descendiente de una clase diferida). Una característica también puede ser diferida mediante cláusula deferred en lugar de una cláusula do. Si una clase tiene características diferidas se ha de declarar como diferida, pero, no obstante una clase sin características diferidas puede ser diferida por sí misma. Las clases diferidas juegan un papel parecido al de las interfaces en lenguajes como Java, a pesar de que muchos teóricos de la programación orientada a objetos crean que las interfaces son en gran medida una respuesta a la falta de Java de herencia múltiple (que tiene Eiffel).

Cambio de nombre

[editar]

Una clase que hereda de otra u otras obtiene todas sus características, por defecto con sus nombres originales. Puede cambiar el nombre a través de la cláusula rename. Eso es necesario en el caso de herencia múltiple si hay conflictos de nombres entre las características heredadas, sin cambiar el nombre, la clase resultante violaría el principio de no sobrecargar, antes mencionada, y por tanto, no sería válida.

Tuples

[editar]

Los tipos tuples pueden ser vistos como una forma simple de clase, proporcionando solo los atributos y el correspondientemente método "set". Un tipo tupla típico

  TUPLE [nom: STRING; pes: REAL; data: DATE]

podría ser utilizado para describir una simple acta de nacimiento si no fuese necesaria una clase. Un ejemplo de esta tupla es simplemente una secuencia de valores con el tipo dado, entre paréntesis, como

  ["Maria", 3.5, anit]

Los componentes de una tupla como tal se pueden acceder si las etiquetas de la tupla son atributos de una clase, por ejemplo, si t ha sido asignado a la tupla entonces t.pes tiene un valor 3.5. Gracias a la noción de asignador de órdenes, la notación de puntos también se puede utilizar para asignar los componentes de esta tupla, como en

  t.pes := t.pes + 0.5

Las etiquetas tuple son opcionales, de manera que también es posible escribir un tipo tupla como TUPLE [STRING, REAL, DATE]. (En algunos compiladores esta es la única forma de tuple, ya que las etiquetas se van introduciendo en el estándar ECMA). La especificación precisa de, por ejemplo, TUPLE [A, B, C] que describe secuencias de al menos tres elementos, el primero de tres que son de los tipos A, B, C, respectivamente. Como resultado TUPLE [A, B, C] se ajusta a (se puede asignar a) TUPLE [A, B], a TUPLE [A] y TUPLE (sin parámetros), la tuple más grande se ajusta a todas las otras tuples.

Agentes

[editar]

El mecanismo del' "agente" de Eiffel agrupa les operaciones dentro de los objetos. Este mecanismo puede ser utilizado por la interacción, la programación dirigida por eventos, y en otros contextos es útil para pasar operaciones alrededor de la estructura del programa. Otros lenguajes de programación, especialmente los que hacen énfasis en la programación funcional, permiten un patrón similar con las continuaciones, clausuras, o generadores; los agentes Eiffel enfatizan el paradigma de los lenguajes orientados a objetos, y usa una sintaxis y semántica similares a los bloques de código en Smalltalk y Ruby. Por ejemplo, para ejecutar el bloque accion_propia para cada elemento de lista_propia, se podría escribir:

  lista_propia.do_all (agent accion_propia)

Para ejecutar accion_propia solo los elementos que satisfacen condicion_propia, una limitación de filtro se puede añadir:

  lista_propia.do_ifsi (agent accion_propia, agente condicion_propia)

En estos ejemplos, accion_propia y condicion_propia son rutinas. Prefijándolos con agente cede un objeto que representa la rutina correspondiente, con todas sus propiedades, en particular, la capacidad de ser llamado con los argumentos adecuados. Así que si a representa un objeto (por ejemplo, porque a es el argumento para do_all), la instrucción

  a.call ([x])

llamara a la rutina original con el argumento x, como si hubiesen llamado directamente a la rutina original: accion_propia (x). Los argumentps para llamar se pasan como una tupla, aquí [x]. Es posible mantener algunos argumentos para un agente abierto y hacer los otros cerrados. Los argumentos abiertos se pasan como argumentos para la llamada (call): que se proporcionan en el momento de utilizar el agente. Los argumentos son siempre cerrados en el momento de la definición del agente. Por ejemplo, si acción2 tiene dos argumentos, la iteración

  lista_propia.do_all (agent acción2 (?, y))

itera acción2 (x, y) para valores sucesivos de x, donde el segundo argumento ha quedado establecido en y. El signo de interrogación? indica un argument abierto, y es un argumento cerrado del agente. Hay que tener en cuenta que la sintaxis básica agent f es una abreviatura de agent f (?,?,...) con todos los argumentos abiertos. También es posible crear el target de un agente libre a través de la notación {T}? donde T es el tipo del objetivo. La distinción entre operandos abiertos y cerrados (operandos = argumentos + target) corresponde a la distinción entre las variables libres i ligades en el cálculo lambda. Un agente de expressión, como acción2 (?, y) con algunos operandos cerrados y algunos abiertos corresponde a una versión de la operación original currificada sobre los operandos cerrados. El mecanismo de agent ha estado recientemente generalizado por permetro la definición de un agent sin hacer referencia a una rutina existente (como accion_propia, condicion_propia, acción2), a través de agentes en línea como en lista_propia.do_all (agent (s: STRING)

    require
        no_void: s /= Void
    do
        s.append_character (',')
    ensure
        appended: s.count = old s.count + 1
    end)

El agente en línea se ha pasado aquí puede tener todos la elementos de una rutina normal, incluyendo precondición, postcondición, la cláusula de rescate (aquí no se usa), y una signatura completa. Esto evita la definición de rutinas cuando todo lo que se necesita es un cálculo que se agrupara en un agent. Esto es útil en particular para los contratos, como en una cláusula invariante que expresa que todos los elementos de una lista son positivos:

  lista_propia.for_all (agent (x: INTEGER): BOOLEAN do Result := (x > 0) end)

El mecanismo agent actual deja una posibilidad de error en tiempos de ejecución (en caso de una rutina con n argumentos se pase a un agent que está esperando m arguments siendo m < n). Esto puede evitarse mediante un control en tiempo de ejecución a través de la precondición valid_arguments de la llamada (call). Hay diversas propuestas para una corrección puramente estática de este problema, incluyendo una propuesta de camabio en el lenguaje de Ribet y otros.[5]

Rutinas de ejecución única

[editar]

El resultado de una rutina puede ser almacenado en memoria caché y la palabra clave once en lugar de do. Las llamadas a una rutina de estos tipos, salvo la primera vez, no requieren cálculos adicionales o la asignación de recursos, sino que simplemente devuelve un resultado previamente calculado con la primera llamada. Un patrón común para las "funciones de ejecución única" es proporcionar objetos compartidos, la primera llamada creara el objeto, a las subsiguientes volverá la referencia a este objeto. El esquema típico es:

objecte_compartido: ALGUN_TIPO
    once
        create Result.fer (args)
             -- Esto creara el objeto y volvera una referencia a la misma a través de 'Result'.
    end  --objeto_compartido

El objeto retornado -Result en el ejemplo- en si puede ser mutable, pero su referencia sigue siendo la misma.

A menudo, las "rutinas de ejecución única", realizan una inicialización necesaria: múltiples llamadas a una library que pueden incluir una llamada al procedimiento de inicialización, pero solo la primera llamada se realizan las acciones requeridas. Usando este patrón la inicialización puede ser descentralizada, evitando la necesidad de un módulo especial de inicialización. Las "rutinas de ejecución única" son similares en propósito y efecto al patrón Singleton de muchos lenguajes de programación, y para el patrón utilizado por Borg en Python.

Por defecto, una "rutina de ejecución única" se llama una vez por hilo de ejecución. La semántica se puede ajustar a una vez por proceso o una vez por objeto calificando con una palabra clave "once", por ejemplo, once ("PROCÉS").

Conversiones

[editar]

Eiffel proporciona un mecanismo que permite las conversiones entre diferentes tipos. El mecanismo coexiste con el de herència y el de complementa. Para evitar cualquier confusión entre los dos mecanismos, el diseño ha de cumplir el siguiente principio:

(Principio de conversión) Un tipo no puede al mismo tiempo ajustarse y convertirse en otro.

Por ejemplo DIARIO puede ajustarse a PUBLICACIÓN, pero INTEGER (enter) se convierte en REAL (y no hereda de él).

El mecanismo de conversión simplemente generaliza las normas ad hoc de conversión (tal y como entre enteros -INTEGER- y reales -REAL-) que hay a la mayoría de los lenguajes de programación, haciéndole entonces aplicable a cualquier tipo siempre que se respecte este principio. Por ejemplo, una clase DATA puede ser declarada para convertir en STRING; lo que hace posible la creación de un text a partir de un data simplemente a través de

   my_string := my_data

como un acceso directo para el uso de la creación explícita de un objeto con un procedimiento de conversión:

   create my_string.make_from_date(my_data)

Para hacer la primera forma posible como un sinónimo de la segunda, hay bastante con incluir el procedimiento de creación (constructor) make_from_date en una cláusula convert al comienzo de la clase.

Como en otro ejemplo, si existe un procedimento de conversión incluye en TUPLE [dia: INTEGER; mes: STRING; num_any: INTEGER], entonces uno puede asignar directamente una tupla a una data, haciendo que la conversión apropiada, como en

      Dia_de_la_Bastilla := [14, "Julio", 1789]

Tratamiento de excepciones

[editar]

El Manejo de excepciones en Eiffel es basa en los principios de diseño por contrato. Por ejemplo, se produce una excepción cuando quien llama a una rutina no satisface la precondición, o cuando en una rutina no se puede garantizar el cumplimiento de la postcondición. En Eiffel, el tratamiento de excepciones no se utiliza para a les estructuras de control o para corregir errores de los datos de entrada.

Un controlador de excepciones Eiffel se define utilizando la palabra clave rescue. Dentro de la sección rescue, la palabra clave retry ejecuta la rutina de nuevo. Por ejemplo, la siguiente rutina controla el número de intentos de ejecución de la rutina, y solo lo vuelve a intentar un cierto número de veces:

connect_to_server (server: SOCKET)
      -- Connect to a server or give up after 10 attempts.
    require
        server /= Void and then server.address /= Void
    local
        attempts: INTEGER
    do
        server.connect
    ensure
      connected: server.is_connected
    rescue
        if attempts < 10 then
            attempts := attempts + 1
            retry
        end
    end

Esto ejemplo es, sin duda, imperfecto, pero en los programes más simples tendría que estar previsto que pueda fallar la conexión. Pero a la mayoría de los programes sería mejor un nombre de rutina como intenta_connectar_al_servidor y la postcondición no prometía una conexión, dejando a quien la llame el hecho de tomar las medidas apropiadas si la conexión no se ha abierto.

Concurrencia

[editar]

Hay disponibles varias librerías de redes y de hilos de ejecución, como EiffelNet y EiffelThreads. Un modelo de concurrencia de Eiffel, basado en los conceptos de diseño por contrato, es el SCOOP, o Programación Concurrente Simple Orientada a Objetos, aún no forma parte de la definición oficial del lenguaje, pero está disponible como a un "add-on" de ETH Zurich. CAMEO[6]​ es una variación (no implementada) de SCOOP de Eiffel. La concurrencia también interactúa con las excepciones. Les excepciones asíncronas pueden ser un problema (una rutina activa una excepción después de que su llamada se termine).[7]

Sintaxis de operadores y corchetes, las órdenes de asignación

[editar]

La visión del cálculo en Eiffel es completamente orientada al objeto en el sentido que cada operación es relativa a un objeto, el'"objetivo". Así, por ejemplo, una suma

  [1] a + b

es conceptualmente entendida como si se tratase de una llamada a la función

  [2] a.mes (b)

con el objetivo a, la característica mes i el argumento b.

Por descontado, [1] es la sintaxis convencional y la preferida normalmente. La sintaxis del operador hace posible el uso de una o de la otra manera, al declarar la función (por ejemplo, en INTEGER (nombre enter), pero eso se aplica a otras clases básicas y se puede utilizar en cualquier otro para que este operador sea apropiado):

mes alias "+" (un_altre: INTEGER): INTEGER
        -- ... Declaración normal de la función...
    end

La gamma de operadores que pueden utilizarse como un "alias" es bastante amplio, e incluyen operadores predefinidos como "+" pero también "los operadores libres" hechos de símbolos no alfanuméricos. Eso hace posible diseñar notaciones especiales infijos y prefijos, por ejemplo, en aplicaciones de matemáticas y de física.

Cada clase podrá tener una función alias de "[]", el operador "corchete", permito que la notación a [i, ...] como un sinónimo de a.f (i, ...) donde f es la función escogida. Eso es particularmente útil para las estructuras de contenedores, como matrices, tablas hash, listas, etc. Por ejemplo, el acceso a un elemento de una tabla hash con claves string se puede escribir

   numero := Libreta_de_telefonos ["JULI FERRER"]

Las "órdenes de asignación" son un mecanismo de acompañamiento diseñado con el mismo espíritu de permitir la solidez, la conveniente notación reinterpretada en el marco de la programación orientada a objetos. Las órdenes de asignación permiten sintaxis de asignación como llamadas a procedimentos "setter". Una asignación adecuada no puede ser de la forma a.x := v ya que esto viola la ocultación de información, se debe usar una orden setter. Por ejemplo la clase tabla hash puede tener la función y el procedimento

item alias "[]" (clave: STRING): ELEMENT         [3]
      -- El elemento de de la clave 'clave'.
      -- (interrogación del "Getter")
    do
        ...
    end 

put (e: ELEMENT; clau: STRING)
      -- Insertar el elemento 'e', asociándolo con la clave 'clave'.
      -- (ordre "Setter")
    do
        ...
    end --

Después, para insertar un elemento que debe utilizar una llamada explícita a la orden setter:

   [4] Libreta_de_telefonos.put (Nueva_persona, "JULI FERRER")

Es posible escribir este equivalente como

   [5] Libreta_de_telefonos ["JULI FERRER"] := Nueva_persona

(De la misma manera que Libreta_de_telefonos ["JULI FERRER"] es un sinónimo de numero := Libreta_de_telefonos.item ("JULI FERRER")), siempre que la declaración item ahora comienza (substitución de [3]) con

   item alias "[]" (key: STRING): ELEMENT assign put

Eso declara put como una orden de asignación asociada con item y, combinado con los alias de corchetes, hace [5] legal y equivalente a [4]. (También se puede escribir, sin aprovechar los corchetes, como Libreta_de_telefonos.item ("JILL SMITH") := Nueva_persona.)

Nota: La lista de argumentos de la asignación de a está obligada a ser: (el tipo de retorno dea, toda la lista de argumentos de a...)

Propiedades léxicas y sintácticas

[editar]

Eiffel no distingue entre mayúsculas y minúsculas. Eso quiere decir que hacer, hacEr y HACER corresponden todos ellos al mismo identificador. Veamos las "regles de estilo" a continuación.

Los comentarios son introducidos por -- (dos guiones consecutivos) y se extienden hasta el final de línea.

El punto y coma (;), como separador de instruccions, es opcional. La mayoría de las veces el punto y coma es omitido, excepto para separar múltiples instrucciones en una línea. Eso se traduce en menos desorden en la página del programa.

No hay anidación de las declaraciones de las características y de la clase. 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, están todas al mismo nivel.

Se acostumbra a agrupar las características en diferentes "cláusulas de características" para facilitar más la lectura, con un conjunto estándar de etiquetas de característica básica que figuren en un orden estándar, por ejemplo:

class TABLA_HASH [ELEMENT, KEY -> HASHABLE] inherit TABLE [ELEMENT]
  
    feature -- Inicialización 
         -- ... Declaración de las órdenes de inicialización (procedimientos de creación/constructores) ... 
  
    feature -- Acceso 
         -- ... Declaraciones de las consultes no booleanas sobre el estado del objeto, per ejemplo, item ... 
  
    feature -- Informe de situación 
         -- ... Declaraciones de consultes booleanas sobre el estado del objeto, por ejemplo, is_empty... 
  
    feature -- el cambio del elemento 
         -- ... Declaraciones de órdenes que cambian la estructura, por ejemplo, put ... 
  
    -- etc. 
end -- TABLA_HASH

En contraste con los lenguajes de programación funcionales más complicados, Eiffel hace una clara distinción entre las expresiones y las instrucciones. Eso esta en consonancia con el principio de separación orden-consulta del método Eiffel.

Convenciones de estilo

[editar]

Gran parte de la documentación de Eiffel utiliza las convenciones de estilo distintivas, diseñadas para velar por un aspecto consistente. Algunas de estas convenciones se aplican al formato de código en si, y otros para la representación tipográfica estándar del código Eiffel en formatos y publicaciones en las que estas convenciones son posibles.

Mientras que el lenguaje no distingue entre mayúsculas y minúsculas, las normas de estilo de prescriben que los nombres de clase estén totalmente en mayúsculas (LISTA), todo en minúsculas para nombres de características (hacer), e iniciales en mayúscula para las constantes (Avogadro). El estilo recomendado también sugiere el guion bajo (_) para separar los componentes de un identificador de diversas palabras, como en temperatura_media.

La especificación de Eiffel incluye directrices para los textos del programa que muestra en formato composición tipográfica: palabras clave en negrita, identificadores definidos por el usuario y las constantes se muestran en cursiva, los comentarios, los operadores y marcas de puntuación en Roman, con el texto del programa en azul como en el presente artículo para distinguirlo de un texto explicativo. Por ejemplo, el "Hola, mundo!" programa dado anteriormente quedaría de la siguiente manera en la documentación Eiffel:

class

    HOLA_MUNDO
create
   make
feature
   make
   do
      print ("Hola, mundo!")
   end --make
end --HOLA_MUNDO

Interfaces para otras herramientas y lenguajes

[editar]

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

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

Aunque no exista una conexión directa entre Eiffel y C, muchos compiladores son Eiffel (Visual Eiffel no es una excepción) el Código fuente surgido de C como un lenguaje intermedio, a someter a un compilador de C, para la optimización y la portabilidad. El compilador Eiffel de tecomp puede ejecutar cogido Eiffel directamente (como un intérprete) sin tener que pasar a través de un código C intermedio ni emitir código C que se pasara a un compilador de C para obtener el código nativo optimizado. En.NET, el compilador EiffelStudio genera directamente código en CIL (Common Intermediate Language). El compilador SmartEiffel puede también generar la salida en bytecode de Java.

Notas y referencias

[editar]
  1. Object-Oriented Software Construction, Second Edition, by Bertrand Meyer, Prentice Hall, 1997, ISBN 0-13-629155-4
  2. ECMA International: Standard ECMA-367 —Eiffel: Analysis, Design and Programming Language 2nd edition (June 2006); disponible a www.ecma-international.org/publications/standards/Ecma-367.htm
  3. International Organisation for Standardisation: Standard ISO/IEC DIS 25436, disponible a [1]
  4. Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October–November 2001, disponible en línea
  5. Philippe Ribet, Cyril Adrian, Olivier Zendra, Dominique Colnet: Conformance of agents in the Eiffel language, in Journal of Object Technology, vol. 3, no. 4, April 2004, Special issue: TOOLS USA 2003, pp. 125-143. Available on line from the JOT article page
  6. Brooke, Phillip; Richard Paige (2008). «Cameo: An Alternative Model of Concurrency for Eiffel». Formal Aspects of Computing (Springer). doi:10.1007/s00165-008-0096-1. 
  7. Brooke, Phillip; Richard Paige (2007). «Exceptions in Concurrent Eiffel». Journal of Object Technology 6 (10): 111-126. 

Enlaces externos

[editar]
  • tecomp "The Eiffel Compiler" / Compilador con licencia GPL de Eiffel
  • SmartEiffel Archivado el 13 de abril de 2011 en Wayback Machine. Compilador de GNU con licencia GPL de Eiffel
  • Eiffel Software: la compañía de Bertrand Meyer, ofrece Eiffel Studio bajo licencia GPL o comercial.
  • NICE: Consorcio internacional para el lenguaje Eiffel