Az Eiffel programozási nyelv

Utasítások, vezérlési szerkezetek, iterátorok

Utasításkészlet

Az Eiffel nyelv tervezésekor lényeges szempont volt az, hogy az utasításkészlet minél egyszerűbb, áttekinthetőbb és kompaktabb legyen. Ennek érdekében például kihagyták a nyelvből a szekvencia kötelező jelölését és a blokkstruktúrát. Rövid, könnyen megjegyezhető kulcsszavakat vezettek be, csak a legszükségesebb funkciókra. Amit lehetett, a nyelv utasításkészletén kívül, a library-rendszerben helyeztek el. (Ld. még szabványos könyvtárak.)

Szekvencia (Compound)

A szekvencia Eiffelben egyszerűen úgy kódolható, hogy a tagjait egymás után írjuk pontosvesszővel elválasztva. Elhatároló kulcsszavakra, mint például a begin és az end a Pascal-ban, nincs szükség. A szekvencia állhat 0 tagból is, ekkor üres utasítást jelent. A szintaxis úgy van megtervezve, hogy a pontosvesszők akár el is hagyhatók, de használatuk ajánlott. Ha használjuk a pontosvesszőt, akkor az a Wirth féle nyelvekhez hasonlóan utasítás elválasztóként működik, és nem utasítást lezáró szimbólumként.

Compound = {ut";"...}


A szekvenciát meghatározza az utasítások szövegbeli leírásának sorrendje.

Szemantika:

Ha a Compound nulla utasítást tartalmaz, akkor a számítás terének állapota változatlan marad. Ha a Compound 1 vagy több utasítást tartalmaz, hatása az, hogy végrehajtódik az első utasítása, majd rekurzív módon az a Compound, amit az előzőből az első utasítás elhagyásával kapunk. Vagyis amilyen sorrendben megjelennek az utasítások, végrehajtjuk őket.

Null utasítás

Nem jelenik meg a szintaxisban. Hatása: a számítás terének állapota változatlan marad. Szerepe, hogy a fölösleges zárójelekből ne legyen baj.

Elágazás

A többi modern programozási nyelvhez hasonlóan az Eiffelben is kétféle elágazás utasítás van. Az egyik az if utasítás, ami tetszőleges elágazás kódolására alkalmas.

Példa:

if a.item(i) < x then u := i + 1; elseif a.item(i> > x then v := i - 1; else found := true; end


Az elseif és else részek természetesen opcionálisak. Az utasítás szemantikája ugyanaz, mint az Ada nyelv if utasításáé. A másik a többirányú elágazás (inspect), ami leginkább a Modula-2 case utasításához hasonlít. Egy INTEGER vagy CHARACTER típusú kifejezés értékét lehet vele összehasonlítani megfelelő típusú konstansokkal, és egyezés esetén egy utasítássorozatot végrehajtani.

Példa:

inspect c when 'a'..'z', 'A'..'Z' then letter := letter + 1 when '0'..'9' then digit := digit + 1 when '%N' then lines := lines + 1; else special := special + 1 end


Mint azt a példából is láthatjuk, az inspect utasítás ágaiban nem csak különálló konstansok, hanem intervallumok és felsorolás is szerepelhetnek. Az ágaknak diszjunktaknak kell lennie, a bennük szereplő konstansok típusának szigorúan meg kell egyezni a vizsgált kifejezés típusával. Az else rész itt is elmaradhat, de ha a vizsgált kifejezés értéke nem egyezik meg egyik konstans értékével sem, tehát a megadott konstansok nem fedik le a teljes értéktartományt, akkor kivétel váltódik ki (a kódja invalid_inspect_value). (Ld. még kivételkezelés.)

Eiffel-ben ugyan nem létezik felsorolási típus, mégis adódik egy lehetőség a helyettesítésére: a unique attribútumok fogalma.

Single, Married, Divorced, Widowed : INTEGER is unique;


Ez négy egész konstanst eredményez, amelyekről azt lehet tudni, hogy pozitív egész értékek, különbözőek, és az egy deklarációban szereplők egymás után következnek (tehát így rendezés is van) - és ezek is használhatóak többirányú elágazásban.

Példa:

inspect n when Single, Divorced then ... when Married then ... when Widowed then ... end


Minden unique konstanst ugyanabban az osztályban kell bevezetni (különben nem biztos, hogy különbözőek az értékek), és ha nem csak unique-ot vizsgálunk, akkor az negatív vagy 0 kell legyen, hogy biztosan ne essen egybe egyikkel sem. A szemantika leíráshoz bevezetjük az ún. "feloldott formát". Ez azt jelenti, hogy úgy tekint minden intervallumot, mintha minden benne szereplő érték fel lenne sorolva. Pl.:

'i'..'n' -t mint 'i', 'j', 'k', 'l', 'm', 'n' -t 5..3 -- üres lista


Szabály:

Egy többirányú elágazás utasítás akkor és csak akkor érvényes, ha a feloldott formára a következő feltételek teljesülnek:

  • Az inspect kifejezés INTEGER vagy CHARACTER típusú.
  • Az inspect konstansok (a különböző választék részben az értékek) ugyanolyan típusú konstansok, mint az inspect kifejezés.
  • Bármely két nem unique inspect konstansnak különböző az értéke.
  • Bármely két unique inspect konstansnak különböző az neve.
  • Ha bármelyik inspect konstans unique, akkor az összes többi is vagy unique, vagy negatív, vagy 0 értéke van.
  • Minden unique inspect konstansnak (ha van) ugyanaz az eredet osztálya (a tartalmazó osztály vagy egy valódi őse).

    Az utasítás hatása az ő feloldott formájára van megfogalmazva: kiszámítja az inspect kifejezés értékét. Ez legfeljebb egy inspect konstanssal lehet egyenlő az előző kikötések miatt. Ha van ilyen, akkor a megfelelő inspect konstans when-je után következő Compound-ot hajtja végre. Ha nincs, akkor:

  • Ha van else ág, azt hajtja végre.
  • Ha nincs else ág, exception-t vált ki (a Kernel Library EXCEPTIONS osztályából az invalid_inspect_value-t), és a rutin végrehajtás abbamarad.


    Vigyázat, a feltételes és többirányú elágazás utasítás különbözőképpen kezeli a hiányzó else ágat, ha a feltételek egyike sem teljesül. A feltételes utasítás ilyenkor egy üres utasítást hajt végre, de a többirányú elágazás exception-t vált ki. Ennek oka az utasítások természetéből adódik: egy feltételes utasítás sorban kipróbálja a lehetőségek egy sorozatát, míg valamelyik esetleg bekövetkezik. Egy többirányú elágazás összehasonlítja egy fix konstans-halmazzal, és ha nem egyezik meg az egyikkel ezek közül, akkor az else ágat hajtja végre. Ezért lehet else-t üresen is írni, de ha nem írok, azt jelenti, hogy meg vagyok győződve arról, hogy az érték beleesik valamelyik ágba. Ha mégsem - akkor exception.

    Egy megjegyzés a kiválasztó utasításokról

    Más nyelvekből is ismerünk egy case vagy switch utasítást. De vigyázzunk, hogy nehogy rosszul használjuk az Eiffelben! Amikor egy rendszernek arra van szüksége, hogy számos lehetséges tevékenység közül kiválasszon egyet, a megfelelő technika nagyon gyakran nem az, hogy explicite beteszteljük az összes lehetséges esetet, hanem egy sokkal rugalmasabb, öröklődésen alapuló technika: a dinamikus összekapcsolás. Az explicit teszteknél minden lehetséges választást fel kell tüntetni - ez egy veszélyes gyakorlat, hiszen egy software project kifejlesztése során mindenképpen lesznek olyan lehetőségek, amelyeket vagy hozzá kell vegyünk, vagy el kell vegyünk belőle. A dinamikus összekapcsolás segít elkerülni ezt. A többirányú elágazás használatát csak olyan egyszerű esetekre kell fenntartani, ahol egy - egyetlen - művelet egy fix és jól ismert választék halmazától függ, amelyek karakterenként vagy egészként reprezentálhatóak.

    Ha a választék egy adattípus variánsait reprezentálja (pl. alkalmazottak különböző kategóriáit, ahol pl. a fizetést másképp kell kiszámítani), akkor a többirányú elágazás nem megfelelő - ekkor ehelyett inkább különböző osztályokat kell definiálni, amelyek egy közös őstől örökölnek (pl. MANAGER, ENGINEER stb. az EMPLOYEE ) és egy vagy több jellemzőt újradefiniálni ( mint pl. a pay_salary), a lokális kontextusnak megfelelően. És akkor a dinamikus összekapcsolás fogja meghatározni a megfelelő variánst. Pl. a Caroline.pay_salary a Caroline exact típusának megfelelő pay_salary-t fogja hívni.

    Sokkal egyszerűbb, ha írunk egy új leszármazottat az EMPLOYEE-nak pl. SECRETARY-t, ha új variánsra van szükségünk.

    Az explicit választéknak azért marad szerepe - pl. az előző egyetlen karakterből álló input feldolgozása és a megfelelő tevékenység végrehajtása. Itt az elágazás csak az első szintű szétválasztást végzi - betűk, számok, vezérlő karakterek. Ezen belül - már a dinamikus összekapcsolódás segítségével megy a dolog. Pl. a betűket használjuk, hogy egy parancs-táblát indexeljünk.

    Ciklus

    Ciklusok kódolására az Eiffel a legtöbb programozási nyelvvel ellentétben csak egy utasítást ad. Ennek szintaxisa a következő:

    from előkészítő utasítások [invariant invariáns állítás] [variant variáns függvény] until kilépési feltétel loop ciklusmag end


    Ez a ciklus nagyjából megfelel a módszertanból ismert ciklusnak. Elöltesztelő, de a legtöbb nyelvvel ellentétben nem a ciklusfeltételt, hanem annak negáltját kell megadni (vagyis azt, hogy mikor lépünk ki). Az invariáns állítás egy logikai kifejezés, a variáns függvény pedig egy egész kifejezés. A program jelentését nem befolyásolják, szerepük a ciklus helyességének ellenőrzésében van. A ciklusinvariáns értékének igaznak kell lennie a ciklusba belépéskor, valamint a ciklus futása közben mindvégig. A variáns függvény értéke egy egész szám, melynek a ciklusba belépéskor pozitívnak kell lennie, a ciklusmag minden lefutásakor csökkennie kell, és a ciklusból kilépéskor is pozitív értékkel kell rendelkeznie. Ha ezek a feltételek futás közben bármikor megsérülnek, kivétel váltódik ki. (Ld. még kivételkezelés , helyességbizonyítás .) A ciklusinvariáns és a variáns függvény megadása nem kötelező, a from kulcsszóval bevezetett inicializáló rész viszont nem hagyható el. Ha nem szükséges az előkészítő utasítássorozat, akkor helyén üres utasítást lehet használni.

    Debug utasítás

    Ez egy fordítási opciótól függően hajt végre bizonyos utasításokat:

    debug -- vagy debug("GRAPHICS_DEBUG")
    instr1; instr1;
    ...
    instrn; instrn;
    end end


    Ha a debug opció off, akkor nem veszi figyelembe végrehajtáskor, ha on, akkor szépen sorban végrehajtja. A környezet lehetőséget kell adjon a ki- és bekapcsolásra, a default az off. Debug_key is használható, ekkor bizonyos debug_key-kre kell bekapcsolható legyen.

    Iterátorok

    Az iterátorokat tulajdonképpen általánosított vezérlési szerkezeteknek tekinthetjük, melyek megadására szintén lehetőség van Eiffel-ben, bár szigorúan nem részei a nyelv magjának, hanem a hozzá tartozó library-rendszerben találhatjuk meg őket. Az Eiffel library-hez tartozik az ITERATOR osztály definiciója, mely egy speciális adatszerkezet (TRAVERSABLE) elemein tud műveleteket végezni. Ebben az osztályban a különböző vezérlési szerkezetek általánosított változatai vannak megvalósítva: az if, a while, az until, stb.

  •