Az Eiffel programozási nyelv

Absztrakt adattípusok, generic-ek

Absztrakt adattípusok

Az Eiffel egy osztály-orientált programozási nyelv, így eszközeivel nagy mértékben támogatja absztrakt adattípusok létrehozását. Az osztályokat a class kulcsszóval kezdve kell megadni, utána a feature kulcsszó után kell az adattagokat és a metódusokat felsorolni. (Ld. még OOP.)

Példa:

class ACCOUNT feature balance : INTEGER; owner : PERSON; minimum_balance : INTEGER is 100; open(who : PERSON) is -- Assign the account to owner who do owner := who end; -- open deposit(sum : INTEGER) is -- Deposit sum into the account do add(sum) end; -- deposit withdraw(sum : INTEGER) is -- Withdraw sum from account do add(-sum) end; -- withdraw may_withdraw(sum : INTEGER) : BOOLEAN is -- Is there enough to withdraw sum? do Result := (balance >= sum + minimum_balance) end -- may_withdraw feature {NONE} add(sum : INTEGER) is -- Add sum to the balance (secret procedure) do balance := balance + sum end; -- add end -- class ACCOUNT

A szelektív láthatóság segítségével könnyedén elrejthető egy típus teljes reprezentációja. Ennek talán az egyetlen szépséghibája az, hogy öröklődéskor az ősosztályban meghatározott láthatósági viszonyokat a leszármazott felüldefiniálhatja. Így a korábban elrejtett reprezentációs részek akár mindenki számára is láthatóvá válhatnak.

Eiffel-ben nincs elkülönített eszköz arra, hogy egy absztrakt adattípus specifikációját elválasszuk az implementációjától (mint pl. Java-ban az interface). Viszont a nyelv osztályfogalma annyira rugalmas, hogy akár ezt is megvalósíthatjuk vele, a következőképpen: a kívánt adattípust egy deferred osztály formájában adjuk meg, melynek minden metódusát deferred-ként definiáljuk. Mivel az Eiffel többszörös és ismételt öröklődésre is lehetőséget ad, ez a módszer hiány nélkül alkalmas független specifikációk írására. Itt érdemes hozzátenni, hogy Eiffel-ben egy alprogram feature specifikációjához hozzátartozik az elő- és utófeltételek megadása is. Ennek leginkább éppen ilyen esetekben van értelme, ahol az alprogram törzsét nem adjuk meg, mégis megkötéseket szeretnénk tenni annak működésére (a szükséges kiindulási állapotra és a végeredményre). (Ld. még helyességbizonyítás.)

Egy osztály leírása a kliensei számára

Érdemes még itt megemlíteni, hogy Eiffel-ben lehetőség van egy általunk készített osztályról leválasztani a specifikációs részeket, elsősorban dokumentációs célokkal. Ezt short formának illetve flat-short formának nevezzük. A short formában csupán az általunk definiált publikus feature-ök fejlécét találhatjuk meg, valamint a hozzájuk tartozó helyességbizonyítást támogató elemeket (elő- és utófeltételek, osztályinvariáns, stb.). A flat-short forma a short formát alkotó részeken kívül még az örökölt publikus feature-ök specifikációját is tartalmazza. Ezek a formák szintaxisukban lényegesen eltérnek a valódi Eiffel kódoktól, a keveredés lehetőségének elkerülése végett. Az Eiffel fejlesztőkörnyezet felkínál olyan eszközöket, melyek egyrészt egy osztály teljes definíciójából elkészítik a short (short) illetve flat-short (flat) formát, másrészt a short formából lefordítható kódot generálnak, deferred osztályt készítve a specifikációból.

Tehát az osztály interface dokumentációja (shortform) tartalmazza:

  • a jellemző deklarációk nevét, formális paramétereit, típusát;
  • minden rutinhoz az első megjegyzés-sort;
  • azon rutinok előfeltételét és utófeltételét, amelyek exportált jellemzőkre vonatkoznak;
  • az osztály invariáns exportált jellemzőkre vonatkozó záradékait.

    Nem tartalmazza az implementáció-függő elemeket:

  • a nem exportált jellemzők leírását;
  • a törzseket;
  • a többi megjegyzés-sort.

    Lehetséges egy B osztály számára short formát generálni, ez a B által elérhető információkat fogja tartalmazni. Flat-short forma esetén az öröklött jellemzőkről is kapunk egy ugyanilyen szerkezetű listát, természetesen figyelembe véve az átnevezéseket és átdefiniálásokat. (Ez a lista általában nem tartalmazza az ANY osztálytól öröklött jellemzőket, de van ilyen opciója is a parancsnak.)

    Példa:

    -- One-way linked lists class interface LINKED_LIST[T] feature specification put_right(v : like first) -- Put v to the right of cursor position. -- Do not move cursor. ... end interface -- class LINKED_LIST



    Generic-ek

    Eiffel-ben lehetőség van generic osztályok létrehozására is. Erre nincs külön kulcsszó a nyelvben, mint pl. az Adában, hanem csupán egy osztály definiálásakor kell szögletes zárójelek között a formális paramétereket megadni. Eiffel-ben generic paraméterként csak típus állhat, hiszen egyetlen önálló egysége az osztály. Egy típust úgy kaphatunk egy generic osztályból, hogy minden formális generic paraméterre megadunk egy aktuális típus paramétert.

    Példa:

    class LIST [ELEMENT_TYPE] ...


    Itt az ELEMENT_TYPE a generic osztály paramétere. Miután ílymódon megadtuk a generic formális paramétereit, a továbbiakban ezek az osztály definíciójában bárhol állhatnak, ahol a szintaxis típust követel meg: lehetnek feature-ök, visszatérő értékek, vagy lokális változók típusai. Egy generic osztály példányosítása hasonlóan egyszerű, az adott típusú objektum definiálásakor kell a generic aktuális paramétereit megadni. Ettől eltekintve egy generic osztály teljesen úgy viselkedik, mintha egy hagyományos osztály lenne, olyannyira, hogy akár másik generic osztály paramétere is lehet.

    Példa:

    x : LIST [INTEGER];


    Így az x INTEGER-ek listája lesz. Eiffel-ben kétféle generic paraméter létezhet: a megszorítás nélküli és a megszorításos. A megszorítás nélkülire már láttunk példát a korábbiakban. Ez egyben a műveletek halmazát is meghatározza, amelyek a generic törzsén belül a paramétertípussal definiált objektumokra alkalmazhatók. Ha megszorítás nélkül deklaráltuk a generic paramétert, akkor csak azt tudhatjuk róla, hogy mindenképpen az ANY Eiffel osztály leszármazottja, mivel ez az összes felhasználó által készített osztály ősosztálya. Ezért a generic osztály törzsén belül kizárólag az ANY osztályban megadott műveletek alkalmazhatók az ilyen entitásokra.

    Megszorítás is tehető a generic paramétertípusára, de egész másként, mint pl. Adában. Eiffel-ben azt követelhetjük meg, hogy a paraméter típus leszármazottja legyen valamely már létező osztálynak. Ezen keresztül elérhető, hogy a kívánt tulajdonságokkal rendelkezzen, elérhetők legyenek a megfelelő metódusai.

    Példa.:

    class ORDERED_LIST [ELEMENT_TYPE -> COMPARABLE] ...


    Itt a lista elemeire megköveteljük, hogy a COMPARABLE osztály egy leszármazottjának példányai legyenek, azaz legyen rájuk definiálva összehasonlítás művelet. Másik példa a HASH_TABLE osztály: olyan elemek táblázatait írja le, amelyek hozzájuk rendelt kulcsokon keresztül elérhetőek.

    class HASH_TABLE[G,KEY->HASHABLE]...


    Az első paraméter a táblában tárolt elemekre vonatkozik, ezek akármilyenek lehetnek, a második a kulcs, ez a HASHABLE osztály egy leszármazottja kell legyen, amiből az a fontos, hogy rendelkeznie kell egy hash_code egészet visszaadó művelettel. Pl. egy ilyen osztály a STRING, tehát ez lehet aktuális generic paraméter.

    Ez egy elegáns megoldás, de vannak hátrányai is. Például, ha olyan tulajdonságot akarunk megkövetelni, ami teljesül ugyan valamely beépített típusra, de az nem leszármazottja a megszorító osztálynak. Ekkor létre kell hozni egy új, üres törzsű osztályt, mely örököl az elemi típustól, és a megszorító típustól egyaránt, és ezzel példányosítható a generic. Problémás ez a módszer akkor is, ha ugyanazzal a típussal szeretnénk példányosítani a generic-et, csak - tegyük fel - másik rendező művelettel.

    Érdekesség , hogy a tömb az Eiffel-ben nem típuskonstrukció, hanem egy generic osztály, amely a Kernel Library-ben van definiálva. (Ld. még szabványos könyvtárak.)

  •