Llenguatge de programació Eiffel

De Viquipèdia
Dreceres ràpides: navegació, cerca

El llenguatge de programació Eiffel fou concebut el 1985 pel Dr. Bertrand Meyer, és un llenguatge orientat l'objecte pur, dissenyat per desenvolupar de manera eficient programari reutilitzable, extensible i fiable. Va sorgir del món acadèmic com a llenguatge de programació per a l'ensenyament, això pot justificar que la seva sintaxi estigui inspirada en la de Pascal. Avui dia Eiffel és un llenguatge estandarditzat per ISO, forma part dels llenguatges de programació suportats per Microsoft .NET, i està tenint força aplicació a la industria.

Com que el creador d'aquest llenguatge, el Dr. Bertrand Meyer, fou un pioner notable de la programació orientada a l'objecte, va concebre el llenguatge sota la seva visió del desenvolupament de programari i potser per això hi ha un reconeixement general que és el llenguatge de programació orientada a l'objecte més ben dissenyat i més complet. Molts dels conceptes introduïts en aquest llenguatge més tard han aparegut en altres llenguatges com Java o C#.

Característiques[modifica | modifica el codi]

Les característiques clau del llenguatge Eiffel inclouen:

  • Una estructura de programa orientat a objectes en els quals una classe serveix com la unitat bàsica de la descomposició.
  • El disseny per contracte estretament integrat amb el llenguatge d'altres construccions.
  • Gestió de memòria automàtica, generalment aplicat per la recollida d'escombraries (garbage collection en anglès).
  • Herència, inclosa l'herència múltiple, el canvi de nom, redefinició, "seleccionar", herència no conforme, i altres mecanismes destinats a fer que l'herència sigui segura.
  • Programació genèrica amb i sense restriccions.
  • Gestionat d'un sistema de tipus uniforme on la semàntica del valor i de la referència dels quals en tots els tipus, inclosos els tipus bàsics com INTEGER (el nombre enter), estan basats en classes.
  • Seguretat dels tipus (comprovació estàtica dels tipus).
  • Seguretat de l'absència de tipus (definda amb la paraula clau void), o protecció estàtica contra la crida a referències nul·les, a través del mecanisme tipus annexats (attached-types en anglès).
  • Agents, o objectes que agrupen computacions, estretament relacionats amb les clausures i el càlcul lambda.
  • Rutines d'execució única, o rutines que s'avaluen només una vegada, per a objectes compartits i la inicialització descentralitzada.
  • Sintaxi basada en paraules clau seguint la tradició ALGOL/Pascal, però lliure de separadors, en la mesura que els punts i comes són opcionals, amb la sintaxi disponible per definir operadors en rutines.
  • No és sensible a majúscules i minúscules.

Objectius de disseny[modifica | modifica el codi]

Eiffel posa èmfasi a les sentències declaratives per sobre el codi de procediment i intenta eliminar la necessitat de les instruccions de gestió dinàmica de la memòria (bookkeeping en anglès).

Eiffel defuig la codificació trucs o tècniques de codificació destinats a facilitar l'optimització al compilador. L'objectiu no és només per fer més llegible el codi, sinó també per permetre als programadors concentrar-se en els aspectes importants d'un programa sense perdre's en els detalls d'implementació. La simplicitat d'Eiffel està destinada a promoure solucions simples, extensibles i reutilitzables; i fiables als problemes informàtics. Els compiladors per programes d'ordinador escrits en Eiffel proporcionen tècniques extensives d'optimització, com ara la substitució automàtica d'una crida pel codi cridat (automatic in-lining en anglès), que alleugen al programador d'una part de la càrrega, mentre que l'optimització de codi produït és d'una eficiència comparable a la del codi escrit en C++.

Antecedents[modifica | modifica el codi]

Eiffel va ser desenvolupat originalment per Eiffel Software, una empresa originalment anomenada Interactive Software Engineering Inc (ISE), fundada per Bertrand Meyer. El llibre Object-Oriented Software Construction (Construcció de programari orientat a l'objecte) conté un tractament detallat dels conceptes i la teoria de la tecnologia d'objectes que han dut a dissenyar Eiffel.[1]

L'objectiu de disseny del llenguatge Eiffel, les biblioteques (libraries en anglès), i els mètodes de programació és permetre als programadors crear mòduls fiables, de programari reutilitzable. Eiffel suporta herència múltiple, genericitat, polimorfisme, encapsulació, les conversions de tipus segur, i covariància dels paràmetres. La contribució més important d'Eiffel a l'enginyeria de programari és el disseny per contracte (DbC, en són sigles en anglès), en què les assercions, precondicions, postcondicions i els invariants de classe es fan servir per ajudar a garantir la correcció del programa sense sacrificar-ne l'eficiència.

El disseny d'Eiffel es basa en la teoria de la programació orientada a l'objecte, amb només una influència menor d'altres paradigmes o qüestions pel suport del codi heretat. Eiffel formalment suporta tipus abstractes de dades. Sota el disseny d'Eiffel, un text de programari ha de ser capaç de reproduir la seva documentació de disseny del text en si, utilitzant una aplicació formal dels "Tipus Abstractes de Dades".

Les implementacions i entorns[modifica | modifica el codi]

EiffelStudio és un entorn de desenvolupament integrat (IDE, en són les sigles en anglès) disponible en virtut d'un codi obert o una llicència comercial. Ofereix un entorn orientat a l'objecte per a l'enginyeria del programari. EiffelEnvision és un plug-in per a Microsoft Visual Studio que permet als usuaris editar, compilar i depurar projectes Eiffel des del Microsoft Visual Studio IDE. EiffelStudio i EiffelEnvision són gratuïts per a ús no comercial. Hi ha unes altres quatre implementacions de codi obert: "The Eiffel Compiler" tecomp, Gobo Eiffel, SmartEiffel, -la implementació GNU, basada en una versió anterior de llenguatge- i Visual Eiffel.

Diversos llenguatges de programació incorporen elements aportats per primera vegada a Eiffel. Sather, per exemple, es va basar originalment en Eiffel, però ha variat des de llavors, i ara inclou diverses característiques de programació funcional. El llenguatge interactiu d'ensenyament Blue, precursor de BlueJ, també està basat en Eiffel. L'Apple Media Tool inclou basat en Eiffel un Apple Media Language.

Les especificacions i normes[modifica | modifica el codi]

La definició del llenguatge Eiffel és un estàndard internacional de la ISO. L'estàndard va ser desenvolupat per ECMA International, que per primera vegada aprovada la norma, el 21 de juny de 2005, com estàndard ECMA 367, Eiffel: Analysis, Design and Implementation Language. Al juny de 2006, ECMA i ISO van aprovar la segona versió. El novembre de 2006, la ISO va publicar per primera vegada aquesta versió. L'estàndard es pot trobar i utilitzar d'una manera gratuïta en el web de ECMA[2] La versió ISO[3] és idèntica en tots els aspectes excepte el format.

Eiffel Software's, "tecomp: The Eiffel Compiler" i Eiffel-library-developer de Gobo s'han compromès a aplicar l'estàndard; Eiffel Software's EiffelStudio 6.1 and "tecomp: The Eiffel Compiler" implementen alguns dels principals nous mecanismes -en particular, els agents en línia, assignador d'ordres, notació parentitzada, herència no conforme, i els tipus annexats (attached-types en anglès). L'equip de SmartEiffel s'ha apartat d'aquest estàndard per crear la seva pròpia versió del llenguatge, que creuen que està més a prop de l'estil original d'Eiffel. Object Tools no ha revelat si en futures versions del seu compilador d'Eiffel complirà amb l'estàndard.

L'estàndard cita els següents predecessors d'especificacions del llenguatge Eiffel:

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

La versió actual de l'estàndard de juny de 2006 conté algunes inconsistències (per exemple, les redefinicions de la covariància). El comitè de ECMA encara no ha anunciat cap calendari ni en quina direcció es resoldran aquestes inconsistències.

La sintaxi i la semàntica[modifica | modifica el codi]

Estructura general[modifica | modifica el codi]

Un "sistema" o "programa" Eiffel és una col·lecció de classes. Per sobre del nivell de les classes, Eiffel defineix el grup (cluster en anglès), que és essencialment un grup de classes, i possiblement de subgrups (grups niats). Les agrupacions no són una estructura de control sintàctica, sinó més aviat una convenció de l'organització estàndard. Normalment una aplicació Eiffel s'organitzarà amb cada classe en un arxiu separat, i cada grup en un directori o carpeta que conté els fitxers de les classes. En aquesta organització, els subgrups són subdirectoris. Per exemple, en virtut de les convencions estàndard de l'organització i l'entorn, x.e podria ser el nom d'un fitxer que defineix una classe anomenada X.

Una classe conté característiques, que són similars als "membres", "atributs" o "mètodes" en altres llenguatges de programació orientats a l'objecte. Una classe també defineix els seus invariants, i conté altres propietats, com una secció de "notes" per a documentació i metadades. Els tipus estàndard de dades d'Eiffel, com INTEGER, STRING and ARRAY, són tots ells classes.

Cada sistema ha de tenir una classe designada com "arrel" ("root" en anglès), amb un dels seus procediments de creació designat com a "procediment arrel". L'execució d'un sistema consisteix en la creació d'una instància de la classe arrel i en executar el procediment arrel. En general, això crea nous objectes, crida noves característiques, i així successivament.

Eiffel té cinc instruccions bàsiques executables: assignació, creació d'objectes, crida de rutina, condició i iteració. Les estructures Eiffel de control són estrictes en el compliment de la programació estructurada: cada bloc té exactament una entrada i exactament una sortida.

Abast[modifica | modifica el codi]

A diferència de molts llenguatges orientats a l'objecte, però com Smalltalk, Eiffel no permet una assignació en els camps dels objectes, excepte dins de les característiques d'un objecte. Eiffel posa l'accent en amagar la informació i l'abstracció de dades, en requerir interfícies formals per a la mutació de dades. Per dir-ho en el llenguatge d'altres llenguatges de programació orientats a l'objecte, tots els camps Eiffel són "privats", i els mètodes "set" ("setters") són necessaris per modificar-ne els valors. Un resultat d'això és que un mètode "set" pot, i normalment ho fa, implementar els invariants per als quals Eiffel proporciona sintaxi.

"Hola, món!"[modifica | modifica el codi]

El primer contacte amb un llenguatge de programació es fa sovint amb l'ús d'un programa "Hola, món!". Aquest programa escrit en Eiffel podria ser:

class
    HOLA_MON
create
    fes
feature
    fes
        do
            print ("Hola, món!%N")
        end --fes
end --HOLA_MON

Aquest programa conté la classe HOLA_MON. El constructor (rutina creadora) per a la classe, de nom fes, invoca print que és la rutina de la biblioteca del sistema per escriure un missatge "Hola, món!" al dispositiu de sortida.

Disseny per Contracte[modifica | modifica el codi]

El concepte de disseny per contracte és fonamental per Eiffel. Els mecanismes estan estretament integrats amb el llenguatge. Els contractes guien la redefinició de les característiques a l'herència.

  • Precondició de la rutina: l'únic requisit pot ser debilitat per l'herència, qualsevol crida que compleixi amb els requisits de l'avantpassat compleix amb les dels descendents.
  • Postcondició de la rutina: la postcondició només pot ser reforçada per herència; cap resultat garantit per l'ancestre segueix en mans dels descendents.
  • Invariant de classe

A més, el llenguatge suporta una "instrucció de verificació" ("check instruction" en anglès) (una espècie de "asserció") i els invariants de bucle.

Característiques, ordres, i consultes[modifica | modifica el codi]

La propietat principal d'una classe és que conté un conjunt de característiques. Com una classe representa un conjunt d'objectes en temps d'execució, o "casos", una característica és un atribut o una operació en aquests objectes. Hi ha dos tipus de funcions: consultes i ordres. Una consulta proporciona informació sobre una instància. Una ordre modifica una instància.

La distinció consulta-ordre és important per al mètode Eiffel. En particular:

  • Principi d'accés uniforme: des del punt de vista d'un client de programari que fa una crida a una funció de classe, si una consulta és un atribut (camp en cada objecte) o una funció (algorisme) no ha de fer cap diferència. Per exemple, a_vehicle.speed podria ser un atribut, que s'accedeix des de la representació de l'objecte, o pot ser calculat per una funció que divideix la distància pel temps. La notació és la mateixa en ambdós casos, pel que és fàcil canviar la representació, sense afectar la resta del programari.
  • Principi de separació ordre-consulta: Les consultes no han de modificar la instància. Això no és una regla del llenguatge, sinó un principi metodològic. Així doncs, en bon estil Eiffel, un no troba un mètode o funció "get" ("geter") que canviï alguna cosa i torni un resultat, sinó que hi ha ordres (procediments) per canviar els objectes, i consultes per a obtenir informació sobre l'objecte, com a resultat dels canvis anteriors.

Sobrecàrrega[modifica | modifica el codi]

Eiffel no permet la sobrecàrrega d'arguments. Cada nom de característica dins d'una classe sempre s'assigna a una característica específica dins de la classe. Un nom, dins d'una classe, significa una cosa. Aquesta opció de disseny ajuda a la legibilitat de les classes, evitant una de les causes d'ambigüitat sobre quina la rutina serà invocada amb una crida. També simplifica el mecanisme de llenguatge. En particular, això és el que fa possible mecanisme d'herència múltiple d'Eiffel.[4]

Els noms poden, per descomptat, ser reutilitzats en diferents classes. Per exemple, l'operador "+" es defineix en diverses classes: INTEGER, REAL, STRING, etc.

Genericitat[modifica | modifica el codi]

Les classes poden ser genèriques, per expressar que estan parametritzades per tipus. Els paràmetres genèrics apareixen entre claudàtors:

class LLISTA [G] ...

G és conegut com un "paràmetre formal genèric". (Eiffel reserva "argument" per a les rutines, i utilitza "paràmetre" només per les classes genèriques.) Amb aquesta declaració G representa dins de la classe un tipus arbitrari, pel que una funció pot retornar un valor de tipus G, i una rutina pot tenir una argument d'aquest tipus:

camp: G do ... end
posa (x: G) do ... end

La LLISTA [INTEGER] i LLISTA [WORD] són "derivacions genèriques" d'aquesta classe. Combinacions permeses (amb n: INTEGER, w: WORD, il: LLISTA [INTEGER], wl: LLISTA [WORD]) són:

n := il.camp
wl.posa (w)

INTEGER i WORD són els "paràmetres genèrics actuals" en aquestes derivacions genèriques.

També és possible tenir "restriccions" dels paràmetres formals, de manera que el paràmetre real ha d'heretar d'una classe donada, la "restricció". Per exemple, en

   class TAULA_HASH [G, CLAU -> HASHABLE]

una derivació TAULA_HASH [INTEGER, STRING] és vàlida únicament si STRING hereta de HASHABLE (com de fet fa a les típiques biblioteques Eiffel). Dins de la classe, després d'haver restringit CLAU mitjançant HASHABLE que per x: CLAU és possible aplicar a x totes les característiques de HASHABLE, com en x.hash_code.

Fonaments de l'herència[modifica | modifica el codi]

Per heretar d'una altra o altres, una classe inclourà una clàusula d'heretar al principi:

class C inherit
   A
   B
 
-- ... Resta de la declaració de la classe ...

La classe pot redefinir (anul·lar) algunes o totes les característiques heretades. Això ha de ser declarat explícitament al començament de la classe a través de la clàusula redefine subclàusula de la clàusula de herència, com en:

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

Classes i característiques diferides[modifica | modifica el codi]

Les classes es poden definir amb deferred class en lloc de amb class per indicar que la classe no pot ser instanciada directament. Les classes no instanciables es diuen classes abstractes en alguns altres llenguatges de programació orientats a l'objecte. En el llenguatge Eiffel, només es poden crear instàncies una classe "efectiva" (que pot ser un descendent d'una classe diferida). Una característica també pot ser diferida mitjançant clàusula deferred en lloc d'una clàusula do. Si una classe té característiques diferides s'ha de declarar com a diferida, però, no obstant una classe sense característiques diferides potser diferida per si mateixa.

Les classes diferides juguen un paper semblant al de les interfícies en llenguatges com Java, encara que molts teòrics de la programació orientada a l'objecte es creuen interfícies siguin en gran mesura una resposta a la manca de Java de l'herència múltiple (que té Eiffel).

Canvi de nom[modifica | modifica el codi]

Una classe que hereta d'una altra o altres aconsegueix totes les seves característiques, per defecte amb els seus noms originals. Pot, però, canviar-ne el nom a través de la clàusula rename. Això és necessari en el cas d'herència múltiple si hi ha conflictes de noms entre les característiques heretades, sense canviar el nom, la classe resultant violaria el principi de no sobrecarregar abans esmentada i per tant, no seria vàlida.

Tuples[modifica | modifica el codi]

Els tipus tuples poden ser vistos com una forma simple de classe, proporcionant només els atributs i el corresponent mètode "set". Un tipus tupla típic

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

i podria ser utilitzat per descriure una simple d'acta de naixement si no fos necessària una classe. Un exemple d'aquesta tupla és simplement una seqüència de valors amb el tipus donat, entre parèntesis, com

   ["Maria", 3.5, anit]

Els components d'una tupla com a tal es poden accedir si les etiquetes de la tupla són atributs d'una classe, per exemple, si t ha estat assignat a la tupla llavors t.pes té un valor 3.5.

Gràcies a la noció d'assignador d'ordres (vegeu més endavant), la notació de punts també es pot utilitzar per assignar els components d'aquesta tupla, com en

   t.pes := t.pes + 0.5

Les etiquetes tupla són opcionals, de manera que també és possible escriure un tipus tupla com TUPLE [STRING, REAL, DATE]. (En alguns compiladors aquesta és l'única forma de tupla, ja que les etiquetes es van introduir a l'estàndard ECMA).

L'especificació precisa de, per exemple, TUPLE [A, B, C] que descriu seqüències d'almenys tres elements, el primer de tres que són dels tipus A, B, C, respectivament. Com a resultat TUPLE [A, B, C] s'ajusta a (es pot assignar a) TUPLE [A, B], a TUPLE [A] i TUPLE (sense paràmetres), la tupla més gran s'ajusta a totes les altres tuples.

Agents[modifica | modifica el codi]

El mecanisme de l'"agent" d'Eiffel agrupa les operacions dins dels objectes. Aquest mecanisme pot ser utilitzat per a la iteració, la programació orientada a esdeveniments, i en altres contextos en què és útil per passar operacions al voltant de l'estructura del programa. Altres llenguatges de programació, especialment els que posen l'accent en la programació funcional, permeten un patró similar amb les continuacions, clausures, o generadors; els agents Eiffel emfatitzen el paradigma dels llenguatges orientats a l'objecte, i l'ús d'una sintaxi i semàntica similar als blocs de codi en Smalltalk i Ruby.

Per exemple, per executar el bloc accio_propia per a cada element de llista_propia, es podria escriure:

   llista_propia.fer_tot (agent accio_propia)

Per executar accio_propia només en els elements que satisfan condicio_propia, una limitació de filtre i es poden afegir:

   llista_propia.fer_si (agent accio_propia, agent condicio_propia)

En aquests exemples, accio_propia i condicio_propia són rutines. Prefixant-los amb agent cedeix un objecte que representa la rutina corresponent, amb totes les seves propietats, en particular, la capacitat de ser cridat amb els arguments adequats. Així que si un representa aquest objecte (per exemple, perquè una és l'argument per fer_tot), la instrucció

   a.call ([x])

cridarà a la rutina original amb l'argument x, com si haguéssim cridat directament a l'original rutina: accio_propia (x). Els arguments per cridar es passen com una tupla, aquí [x].

És possible mantenir alguns arguments per a un agent oberts (open en anglès) i fer els altres tancats (closed en anglès). Els arguments oberts es passen com a arguments per a la crida (call): que es proporcionen en el moment d'utilitzar l'agent. Els arguments són sempre tancats en el moment de la definició de l'agent. Per exemple, si accio2 té dos arguments, la iteració

   llista_propia.fer_tot (agent accio2 (?, y))

itera accio2 (x, y) per a valors successius de x, on l'argument segon ha quedat establert en y. El signe d'interrogació ? indica un argument obert, y és un argument tancat de l'agent. Tingueu en compte que la sintaxi bàsica agent f és una abreviatura de agent f (?, ?, ...) amb tots els arguments oberts. També és possible crear l'objectiu (target en anglès) d'un agent lliure a través de la notació {T}? on T és el tipus de l'objectiu.

La distinció entre operands oberts i tancats (operands = arguments + objectiu) correspon a la distinció entre les variables lliures i lligades en el càlcul lambda. Un agent d'expressió, com ara accio2 (?, y) amb alguns operands tancats i alguns oberts correspon a una versió de l'operació original currifidada sobre els operands tancats.

El mecanisme d'agent ha estat recentment generalitzat per permetre la definició d'un agent sense fer referència a una rutina existent (com accio_propia, condicio_propia, accio2), a través d'agents en línia com a

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

L'agent en línia s'ha passat aquí pot tenir tota la faramalla d'una rutina normal, incloent precondició, postcondició, la clàusula de rescat (aquí no s'usa), i una signatura completa. Això evita la definició de rutines quan tot el que es necessita és un càlcul que s'agruparà en un agent. Això és útil en particular per als contractes, com a en una clàusula invariant que expressa que tots els elements d'una llista són positius:

   llista_propia.per_a_tots (agent (x: INTEGER): BOOLEAN do Result := (x > 0) end)

El mecanisme agent actual deixa una possibilitat d'error en temps d'execució (en cas d'una rutina amb n arguments es passi a un agent que està esperant m arguments amb m < n). Això pot evitar-se mitjançant un control en temps d'execució a través de la precondició valid_arguments de la crida (call). Hi ha diverses propostes per a una correcció purament estàtica d'aquest problema, incloent una proposta de canvi en el llenguatge de Ribet i altres.[5]

Rutines d'execució única[modifica | modifica el codi]

El resultat d'una rutina pot ser emmagatzemat en memòria cau (caché en anglès) amb la paraula clau once en lloc de do. Les crides a una rutina d'aquest tipus, llevat de la primera vegada, no requereixen càlculs addicionals o l'assignació de recursos, sinó que simplement retorna un resultat prèviament calculat amb la primera crida. Un patró comú per a les "funcions d'execució única" és proporcionar objectes compartits, la primera crida crearà l'objecte, a les subsegüents tornarà la referència a aquest objecte. L'esquema típic és:

objecte_compartit: ALGUN_TIPUS
    once
        create Result.fer (args)
             -- Això crea l'objecte i retorna una referència a la mateixa a través de 'Result'.
    end  --objecte_compartit

L'objecte retornat -Result a l'exemple- en si pot ser mutable, però la seva referència segueix sent la mateixa.

Sovint, les "rutines d'execució única", realitzen una inicialització necessària: múltiples crides a una biblioteca (library en anglès) que poden incloure una crida al procediment d'inicialització, però només la primera crida es realitzen les accions requerides. Usant aquest patró la inicialització pot ser descentralitzada, evitant la necessitat d'un mòdul especial d'inicialització. Les "rutines d'execució única" són similars en propòsit i efecte al patró singleton de molts llenguatges de programació, i el patró utilitzat per Borg al Python.

Per defecte, una "rutines d'execució única" s'anomena una vegada per fil d'execució (once per thread en anglès). La semàntica es pot ajustar a una vegada per procés o una vegada per objecte qualifica-te'l amb una paraula clau "once", per exemple, once ("PROCÉS").

Conversions[modifica | modifica el codi]

Eiffel proporciona un mecanisme per permetre les conversions entre diferents tipus. El mecanisme coexisteix amb el d'herència i el complementa. Per evitar qualsevol confusió entre els dos mecanismes, el disseny ha de complir el següent principi:

(Principi de conversió) Un tipus no pot al mateix temps ajustar-se i convertir-se a un altre.

Per exemple DIARI pot ajustar-se a PUBLICACIÓ, però INTEGER (enter) es converteix en REAL (i no hereta d'ell).

El mecanisme de conversió simplement generalitza les normes ad hoc de conversió (tal com entre enters -INTEGER- i reals -REAL-) que hi ha a la majoria dels llenguatges de programació, fent-ho llavors aplicable a qualsevol tipus sempre que es respecti aquest principi. Per exemple, una classe DATA pot ser declarada per a convertir en STRING; el que fa possible la creació d'un text a partir d'una data simplement a través de

   string_meu := data_meva

com un accés directe per l'ús de la creació explícita d'un objecte amb un procediment de conversió:

   create string_meu.fer_de_data (data_meva)

Per fer la primera forma possible com a sinònim de la segona, n'hi ha prou amb incloure el procediment de creació (constructor) fer_de_data en una clàusula convert al començament de la classe.

Com a un altre exemple, si existeix un procediment de conversió inclòs en TUPLE [dia: INTEGER; mes: STRING; num_any: INTEGER], llavors un pot assignar directament una tupla a una data, fent que la conversió apropiada, com a

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

Tractament d'excepcions[modifica | modifica el codi]

El tractament d'excepcions en Eiffel es basa en els principis de disseny per contracte. Per exemple, es produeix una excepció quan qui crida a una rutina no satisfà la precondició, o quan a una rutina no es pot garantir el compliment de la postcondició. En Eiffel, el tractament d'excepcions no s'utilitza per a les estructures de control o per corregir errors de les dades d'entrada.

Un controlador d'excepcions Eiffel es defineix utilitzant la paraula clau rescue. Dins de la secció rescue, la paraula clau retry executa la rutina de nou. Per exemple, la següent rutina controla del nombre d'intents d'execució de la rutina, i només ho torna a intentar un cert nombre de vegades:

connecta_al_servidor (servidor: SOCKET)
      -- Es connecta a un servidor o renuncia després de 10 intents.
    require
        servidor /= Void and then servidor.addressa /= Void
    local
        intents: INTEGER
    do
        servidor.connecta
    ensure
        connectat: servidor.es_connectat
    rescue
        if intents < 10 then
            intents := intents + 1
            retry
        end --if
    end --connecta_al_servidor

Aquest exemple és, sens dubte, imperfecte, però en els programes més simples hauria de estar previst que pugui fallar la connexió. Per a la majoria dels programes seria millor un nom de rutina com intenta_connectar_al_servidor i la postcondició no prometria una connexió, deixant a qui la crida el fet de prendre les mesures apropiades si la connexió no s'ha obert.

Concurrència[modifica | modifica el codi]

Hi ha disponibles diverses biblioteques (libraries en anglès) de xarxes i de fils d'execució (threads en anglès), com ara EiffelNet i EiffelThreads. Un model de concurrència d'Eiffel, basat en els conceptes de disseny per contracte, és el SCOOP (programari), o Programació Concurrent Simple Orientada a l'Objecte (Simple Concurrent Object Oriented Programming en anglès), encara no forma part de la definició oficial del llenguatge, però disponible com a un "add-on" de ETH Zurich. CAMEO[6] és una variació (no implementada) de SCOOP d'Eiffel. La concurrència també interacciona amb les excepcions. Les excepcions asíncrones poden ser un problema (una rutina activa una excepció després que la seva crida s'ha acabat).[7]

Sintaxi d'operadors i claudàtors, les ordres d'assignació[modifica | modifica el codi]

La visió del càlcul a Eiffel és completament orientada a l'objecte en el sentit que cada operació és relativa a un objecte, l'"objectiu". Així, per exemple, una suma

  [1] a + b

és conceptualment entesa com si es tractés d'una crida a la funció

  [2] a.mes (b)

amb l'objectiu a, la característica mes i l'argument b.

Per descomptat, [1] és la sintaxi convencional i la preferida normalment. La sintaxi de l'operador fa possible l'ús d'una o de l'altra manera, en declarar la funció (per exemple, a INTEGER (nombre enter), però això s'aplica a altres classes bàsiques i es pot utilitzar en qualsevol altre per als que aquest operador sigui apropiat):

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

La gamma d'operadors que poden utilitzar-se com a "àlies" (alias en anglès) és bastant ampli, i inclouen operadors predefinits com "+" però també "els operadors lliures" fets de símbols no alfanumèrics. Això fa possible dissenyar notacions especials d'infixos i prefixos, per exemple, en aplicacions de matemàtiques de física.

Cada classe podrà, a més, tenir una funció àlies de "[]", l'operador "claudàtor", permetent que la notació a [i, ...] com a sinònim de a.f (i, ...) on f és la funció escollida. Això és particularment útil per a les estructures de contenidors, com ara matrius, taules hash, llistes, etc. Per exemple, l'accés a un element d'una taula hash amb claus string es pot escriure

   numero := Llibreta_de_telefons ["JULI FERRER"]

Les "ordres d'assignació" són un mecanisme d'acompanyament dissenyat amb el mateix esperit de permetre la solidesa, la convenient notació reinterpretada en el marc de la programació orientada a l'objecte. Les ordres d'assignació permeten sintaxi d'assignació com a crides a procediments "setter". Una assignació adequada no pot ser de la forma a.x := v, ja que això viola l'ocultació d'informació, cal usar un ordre setter (procediment). Per exemple la classe taula hash pot tenir la funció i el procediment

camp alias "[]" (clau: STRING): ELEMENT         [3]
      -- L'element de de la clau 'clau'.
      -- (interrogació del "Getter")
    do
        ...
    end --camp
 
posa (e: ELEMENT; clau: STRING)
      -- Insertar l'element 'e', associant-lo amb la clau 'clau'.
      -- (ordre "Setter")
    do
        ...
    end --posa

Després, per inserir un element que ha d'utilitzar una crida explícita a l'ordre setter:

   [4] Llibreta_de_telefons.posa (Nova_persona, "JULI FERRER")

És possible escriure aquest equivalent com

   [5] Llibreta_de_telefons ["JULI FERRER"] := Nova_persona

(De la mateixa manera que Llibreta_de_telefons ["JULI FERRER"] és un sinònim de numero := Llibreta_de_telefons.camp ("JULI FERRER")), sempre que la declaració camp ara comenci (substitució de [3]) amb

   camp alias "[]" (key: STRING): ELEMENT assign posa

Això declara posa com a ordre d'assignació associada amb camp i, combinat amb l'àlies claudàtors, fa [5] legal i equivalent a [4]. (També es pot escriure, sense aprofitar els claudàtors, com Llibreta_de_telefons.camp ("JILL SMITH") := Nova_persona.)

Nota: La llista d'arguments de l'assignació d'a és obligat a ser: (el tipus de retorn d'a, tota la llista d'arguments d'a...)

Propietats lèxiques i sintàctiques[modifica | modifica el codi]

Eiffel no distingeix entre majúscules i minúscules. Això vol dir que fer, fEr i FER corresponen tots ells el mateix identificador. Vegeu, però, les "regles d'estil" a continuació.

Els comentaris són introduïts per -- (dos guions consecutius) i s'estenen fins al final de línia.

El punt i coma (;), com a separador d'instruccions, és opcional. La majoria de les vegades el punt i coma és omès, excepte per separar múltiples instruccions en una línia. Això es tradueix en menys desordre a la pàgina del programa.

No hi ha niament de les declaracions de les característiques i de la classe. Com a resultat l'estructura d'una classe Eiffel és simple: algunes clàusules a nivell de classe (herència, invariant) i una successió de declaracions de característiques, estan totes al mateix nivell.

S'acostuma a agrupar les característiques en diferents "clàusules de característiques" per facilitar-ne més lectura, amb un conjunt estàndard d'etiquetes de característica bàsica que figuren en un ordre estàndard, per exemple:

class TAULA_HASH [ELEMENT, KEY -> HASHABLE] inherit TABLE [ELEMENT]
 
    feature -- Inicialització 
         -- ... Declaracions de les ordres d'inicialització (procediments de creació/constructors) ... 
 
    feature -- Accés 
         -- ... Declaracions de les consultes no booleanes sobre l'estat de l'objecte, per exemple, camp ... 
 
    feature -- Informe de situació 
         -- ... Declaracions de consultes booleanes sobre l'estat de l'objecte, per exemple, es-buida ... 
 
    feature -- el canvi de l'element 
         -- ... Declaracions de ordres que canvien l'estructura, per exemple, posa ... 
 
    -- etc. 
end -- TAULA_HASH

En contrast amb els llenguatges de programació funcionals més enrevessats, Eiffel fa una clara distinció entre les expressions i les instruccions. Això està en consonància amb el principi de la distinció consulta-ordre del mètode Eiffel.

Convencions d'estil[modifica | modifica el codi]

Gran part de la documentació d'Eiffel utilitza les convencions d'estil distintives, dissenyades per vetllar per un aspecte consistent. Algunes d'aquestes convencions s'apliquen al format de codi en si, i altres per a la representació tipogràfica estàndard del codi Eiffel en formats i publicacions en les que aquestes convencions són possibles.

Mentre que el llenguatge no distingeix entre majúscules i minúscules, les normes d'estil de prescriuen que els noms de classe estiguin totalment en majúscules (LLISTA), tot en minúscules per a noms de característiques (fer), i inicials en majúscula per a les constants (Avogadro). L'estil recomanat també suggereix el guió baix (_) per separar els components d'un identificador de diverses paraules, com a temperatura_mitjana.

L'especificació d'Eiffel inclou directrius per als textos de programari que mostra en format composició tipogràfica: paraules clau en negreta, identificadors definits per l'usuari i les constants es mostren en cursiva, els comentaris, els operadors i marques de puntuació en rodona, amb el text del programa en blau com en el present article a distingir-lo d'un text explicatiu. Per exemple, el "Hola, món!" programa donat anteriorment quedaria de la següent manera en la documentació Eiffel:

class

    HOLA_MON
create
   fes
feature
   fes
   do
      print ("Hola, món!")
   end --fes
end --HOLA_MON

Interfícies amb altres eines i llenguatges[modifica | modifica el codi]

Eiffel és un llenguatge purament orientat a l'objecte, però proporciona una arquitectura oberta per a la interconnexió amb programari "extern" en qualsevol altre llenguatge de programació.

És possible, per exemple, programar a nivell màquina i sistema operatiu en C. Eiffel proporciona una interfície senzilla per a les rutines en C, inclòs el suport a "C en línia" (escriure el cos d'una rutina d'Eiffel en C, en general per a petites operacions a nivell màquina).

Encara que no existeix una connexió directa entre Eiffel i C, molts compiladors Eiffel (Visual Eiffel n'és una excepció) el codi font sortit de C com un llenguatge intermedi, a sotmetre's a un compilador de C, per a l'optimització i la portabilitat. El compilador Eiffel de tecomp pot executar codi Eiffel directament (com un intèrpret) sense haver de passar a través d'un codi C intermedi ni emetre codi C que es passarà a un compilador de C per obtenir el codi natiu optimitzat. En .NET, el compilador EiffelStudio genera directament codi en CIL (Common Intermediate Language). El compilador SmartEiffel pot també generar la sortida en bytecode de Java.

Referències[modifica | modifica el codi]

  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 «www.iso.org». [Enllaç no actiu]
  4. Bertrand Meyer: Overloading vs Object Technology, in Journal of Object-Oriented Programming (JOOP), vol. 14, no. 4, October–November 2001, disponible online
  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. «Cameo: An Alternative Model of Concurrency for Eiffel». Formal Aspects of Computing. Springer, 2008. DOI: 10.1007/s00165-008-0096-1.
  7. Brooke, Phillip. «Exceptions in Concurrent Eiffel». Journal of Object Technology, 6, 10, 2007, pàg. 111–126.

Enllaços externs[modifica | modifica el codi]