Eiffel (programozási nyelv)
ElvekAz Eiffel objektumorientált, és ezt igyekszik minél következetesebben megvalósítani. A programkönyvtárak és az alaptípusok is osztályok. A programkönyvtárak használata is objektumorientált: örökölni kell belőlük. Az azonos osztályú objektumok nem látnak bele jobban egymás belsejébe, mint más kliensek. Sok más nyelvvel, például a C++-szal és a Javával ellentétben a leszármazott osztály példányai korlátozások nélkül hozzáférhetnek azokhoz a feature-jeikhez is, amelyeket az alaposztályból örököltek. Tehát az Eiffel nyelv a többi, osztályorientált nyelvvel szemben objektumorientált. Engedélyezi a többszörös öröklődést, és a gyémántprobléma megoldására több eszközt is kínál. Sem az összeolvasztás, sem a szétválasztás nem automatikus. A probléma megoldását a programozóra bízza, és ehhez nyelvi eszközöket is kínál. A nyelv tervezésében fontosak voltak a kényelmi szempontok és az intuíció támogatása is. A leszármazottakban a láthatóság akár szűkíthető is. A rutinok paraméterkészlete, értelmezési tartománya szűkíthető. Ha G generikus osztály, és B alosztálya A-nak, akkor G[B] is alosztálya G[A]-nak, holott az elmélet a másik irányt indokolná. Ezekkel az eszközökkel egyszerűen megvalósíthatók olyan megkötések, amelyek más nyelvekben bonyolult, vagy akár lehetetlen lenne megvalósítani. Mindezek az eszközök azonban aláássák a típusbiztonságot, tehát a típusok nem bizonyítják a program helyességét. A problémán a polimorfikus catcall segíthet. A nyelv alapelvei közé tartozik az általánosítás is. A nyelvhez csatolt módszertanban a projekt külön fázisában végzik az általánosításokat, a projektben szereplő osztályok generikussá tételét. A generikusság korlátozható közös ősosztállyal. Ennek az a hátránya, hogy a közös ősbe be kell tenni minden műveletet, amire hivatkozni kívánunk. Ez részletes előzetes tervezést igényel. Az ágensek segíthetnek megkerülni ezt a kérdést. A helyesség ellenőrzésére az elő- és utófeltételek, meg az invariánsok szolgálnak. Közös néven szerződéseknek nevezik őket, és a vállalkozók közötti szerződésekhez hasonlítják. Még az ős és a leszármazott osztályok is szerződnek, ahol is a leszármazott kapja az alvállalkozó szerepét. Az egyes objektumokban a privát rutinok belsejében nincsenek szerződések; az egyes objektumnak nem kell önmagával szerződnie, de az invariánst a művelet elvégzése után biztosítania kell. Szintaxis és szemantikaAz Eiffel nyelv csak az ASCII karaktereket fogadja el. Ha más karakterek bukkannak fel, akkor a fordító hibát jelez. Beépített típusokAz Eiffel beépített elemi típusai:
A fordító ismeri még a KonvenciókMaga a nyelv nagybetű-érzéketlen: a kis- és a nagybetűk használatát konvenciók szabályozzák. A nevekben csak ASCII karakterek szerepelhetnek; a neveket betűvel kell kezdeni, de a továbbiak lehetnek betűk, számok és aláhúzásjelek is. Az aláhúzásjel a több szavas nevek tagolására szolgál.
Az osztályok neve a konvenció szerint csupa nagybetűből áll. A konstansok nagybetűvel, a többi A Konstans megadása például: Solar_system_planet_count: INTEGER = 9
Vezérlési szerkezetekA feltételes utasítás így néz ki: if feltetel
then
--utasitasok
elseif feltetel
then
--utasitasok
else
--utasitasok
end
ahol akárhány Többszörös elágazás írható ezzel is: inspect --egesz, vagy karakter kifejezes
when ertek1,ertek2
then utasitas
when ertek3..ertek4
then utasitas
else utasitas
end
A ciklus: from
--kezdofeltetel
invariant
--invarians
variant
--ciklusvaltozo
until
--amig nem
loop
--ciklusmag
end
ahol is az RutinokA rutinok a A paraméter nélküli rutinok zárójel nélkül hívhatók. Ez lehetővé teszi, hogy egy absztrakt osztály egyik konkrét utóda kiszámítsa azt, ami egy másik leszármazottban attribútum. A Az elavult rutinok a A felülírás letiltható a ÁgensekA rutinok ágensbe burkolva átadhatók paraméterként. Ezek az ágensek azonban nem azonosak a robotok programozásában használt ágensekkel. Legyen az r rutin definiálva a C osztályban. Ekkor a C.r rutinból ágens készíthető: class C
feature
--...
r(parameterek)
do
--a rutinban megvalositott tevekenyseg
end
agent r
end
Az agent r(a,?)
azt jelenti, hogy az első paraméter az a, a második paraméter nyitott. Hasonlóan, agent r(?,b)
jelentése az, hogy az első paraméter nyitott, a második paraméter a b. De lehet ilyen is: agent r(a,b)
itt minden paraméter meg van adva, de a behelyettesítés még nem történt meg, hanem arra vár, hogy meghívják az ágenst. Lehet akár ilyen is: agent r(?,?)
ami ugyanazt jelenti, mint agent r
. OsztályokOsztályok a Az osztályokban kiemelt szerep jut a létrehozó feature-öknek. Ezek a konstruktoroknak felelnek meg. A létrehozó feature-öket az osztály elején a class
HELLO_WORLD
create
make
feature
make
do
print ("Hello, world!")
end
end
A létrehozó rutinok szokásos neve create x.make(a : INTEGER, b : STRING, c : ACCOUNT)
Osztályon belül nincs túlterhelés, de különböző osztályokban szabad egy műveletet ugyanazon a néven deklarálni. Absztrakt osztályok és rutinok a Az osztályok alapesetben referenciák révén példányosulnak. Ha ezt nem akarjuk, akkor az osztályt expanded class PONT
feature
x, y : REAL
eltol(dx, dy : REAL)
do
x := x + dx
y := y + dy
end
end
Az üres referencia a Void, ami a NONE fiktív osztály egyetlen példánya. Ha egy osztály Az alacsony szintű mutatókat a Az osztályokban ÖröklődésA többszörös öröklődés megengedett: class D
create --...
inherit
A
B
feature
--...
ahol is az ősosztályok nem fontosságuk szerint csökkenő sorrendben vannak felsorolva, mint a Python nyelvben, hanem egyenrangúak. Névütközés esetén a fejlesztő döntheti el, hogy összevonja-e a feature-öket, vagy elkülöníti. Ehhez az Eiffel nyelvi szinten is biztosít eszközöket. Egy feature átnevezhető ( A létrehozó rutinok öröklődnek, de az utódokban már nem lesznek automatikusan létrehozó rutinok. Azokat minden újabb osztály elején új Az öröklődésben az osztályoknak van egy közös őse, az ANY. Ez implementál néhány hasznos feature-t, mint a Az összes osztálynak van egy közös utóda, a NONE fiktív osztály, aminek csak egy eleme van, az üres referencia, a Az ANY és a NONE az exportlistákban válik fontossá: export{ANY} feature xyz
azt jelenti, hogy az xyz feature bárhonnan látható, export{NONE} feature
pedig azt, hogy az adott objektumon kívülről még az azonos osztályú példányok sem férhetnek hozzá. A többi eset ezek között áll, a kapcsos zárójelek között felsorolt osztályú objektumok láthatják az osztály adott feature-ét. Ez a láthatóság finomabb szabályozását teszi lehetővé. SzerződésekAz Eiffel nyelv alapelve a szerződésalapú programozás. Ez azt jelenti, hogy akár minden utasításnak lehet elő-, utófeltétele, vagy invariánsa. Ezek felfoghatók szerződésként a hívó és a hívott között. A hívó biztosítja az előfeltételt és az invariánst, és a hívott vállalja, hogy normális lefutás esetén biztosítja az utófeltételt és az invariánst, kivétel esetén pedig legalább az invariánst. A konstruktoroknak nincs külön előfeltételük, és az invariánst sem kell a hívónak biztosítania, hiszen éppen a konstruktor állítja be az invariánst. Az előfeltételeket a hívó ellenőrzi, ezért nem hívhatók benne olyan rutinok, amiket a hívó nem tud hívni. Az utófeltételben A szerződések alakja abban az osztályban, ahol az öröklésben először definiálják az illető feature-t: feature nev
require
--az elofeltetelt leiro allitasok
do
begin
--a rutin utasitasai
ensure
--az utofeltetelt leiro allitasok
end
invariant
--az invarianst leiro allitasok
Az öröklődés folyamán az előfeltételek enyhülhetnek, az utófeltételek szigorodhatnak. Ha nem írunk elő- vagy utófeltételt, akkor azok azonosan igazak lesznek. Ha egy rutinnak nincs előfeltétele, akkor a továbbiakban sem lehet, viszont az utófeltételben már lehetnek vállalásai. Az előfeltételhet vaggyal, az utófeltételhez éssel lehet továbbiakat hozzávenni: feature nev
require else
--az elofeltetelt leiro allitasok
do
begin
--a rutin utasitasai
ensure then
--az utofeltetelt leiro allitasok
end
Többszörös öröklődés esetén is az előfeltételek összevagyolódnak, az utófeltételek és az invariánsok összeéselődnek. Az Eiffel lehetővé teszi, hogy egy rutint, aminek nem volt paramétere, újraimplementáljunk attributumként. Ekkor az előfeltételek elfelejtődnek, az utófeltételek és az invariánsok az osztály invariánsai lesznek. Az KivételkezelésAz Eiffel nyelv a normál tevékenységtől való eltérést első vonalban a szerződésekkel fogja meg. A kivételek megmaradnak kivételes eseménynek. Akkor kerül rájuk sor, ha az adott rutin nem tudja biztosítani az utófeltételét. Ekkor az az elvárás, hogy legalább az osztályinvariánst állítsa helyre. A kivételkezelésre a rutin törzsén kívül, az Egy Eiffel rutin vázlata a feature nev
do
begin
--a rutin utasitasai
rescue
--a kivételek kezelése
retry
end
Kivételek az EXCEPTIONS osztályból származtathatók. GenerikusokAz általánosítás és az absztrakció az Eiffel nyelv alapelvei közé tartozik. A módszertan kiemelten kezeli az általános, de specializálható szerkezeteket. Bertrand minden projekthez javasol egy általánosítási szakaszt, ahol a projektben megalkotott osztályokat lehetőség szerint általánosítják. Generikusok valósítják meg például az adatszerkezeteket. Egy generikus osztály vázlata: class SHD[G]
feature
--definiciok
end
Egy általános generikusban csak olyan műveletekre szabad hivatkozni, amelyek általánosságban minden osztályra meghívhatók, különben a generikus hibás lesz, és nem fog lefordulni. Megkötésekkel ez a hiba javítható: class SORTABLE_ARRAY[G->COMPARABLE]
feature
--definiciok; hasznalhatja az osszehasonlitast, a COMPARABLE muveleteit
end
Keverhető a nem korlátozottal: class HASH_TABLE[G, H-> HASHABLE]
feature
--definiciok
end
TömbökTömbök megadhatók az ARRAY generikus osztály példányaiként, vagy például így: tomb = <<4, 6, 9>>
Ez egy manifeszt tömb, típusa Manifeszt konstansok stringekhez is elérhetők: INTEGER = "Go get a life!"
Használható az a, b, c, n = unique
A fordító ad nekik értéket. Ez pótolja a felsorolási típust. Tuple és rutin típusokA TUPLE az Eiffel direkt szorzat típusa. Hasonlít a generikusokra, de nem az, hiszen akárhány paramétere lehet: TUPLE[] = TUPLE :> TUPLE[STRING]
TUPLE[STRING] :> TUPLE[STRING, INTEGER]
TUPLE[STRING, INTEGER] :> TUPLE[STRING, INTEGER, STRING]
--...
ahol is a hosszabb TUPLE a kezdőszeletét tartalmazó TUPLE[] = TUPLE
TUPLE[STRING] <: TUPLE[ANY]
TUPLE[STRING, INTEGER] <: TUPLE[ANY, ANY]
TUPLE[STRING, INTEGER, STRING] <: TUPLE[ANY, ANY, ANY]
--...
A rutin típusok leszármazása: A rutinok típusa a ROUTINE[TUPLE[]] = ROUTINE[TUPLE] = ROUTINE :> ROUTINE[TUPLE[STRING]]
ROUTINE[TUPLE[STRING]] :> ROUTINE[TUPLE[STRING, INTEGER]]
ROUTINE[TUPLE[STRING, INTEGER]] :> ROUTINE[TUPLE[STRING, INTEGER, STRING]]
--...
valamint ROUTINE[TUPLE[]] = ROUTINE[TUPLE] = ROUTINE
ROUTINE[TUPLE[STRING]] <: ROUTINE[TUPLE[ANY]]
ROUTINE[TUPLE[STRING, INTEGER]] <: ROUTINE[TUPLE[ANY, ANY]]
ROUTINE[TUPLE[STRING, INTEGER]] <: ROUTINE[TUPLE[ANY, ANY, ANY]]
--...
ahol a TUPLE-k a paramétereket tartalmazzák. A függvények általános típusa hasonló, csak kibővül a visszatérési értékkel: FUNCTION[TUPLE, T]
ahol T a visszatérési érték típusa. Az altípusok a ROUTINE altípusaihoz hasonlóan képződnek, a visszatérési érték figyelembe vételével. A rutin típusok az ágensbe való burkoláskor válnak fontossá. Példaprogramclass
HELLO_WORLD
create
make
feature
make
do
io.put_string ("Hello, world!")
io.put_new_line
end
end
Jegyzetek
Források
|
Portal di Ensiklopedia Dunia