Eiffel

Objavljeno: 5.6.2006 21:35 | Avtor: Uroš Mesojedec | Kategorija: Programer | Revija: Junij 2004

Razliko med Evropejci in Američani včasih presenetljivo nazorno pokažejo celo programski jeziki. Ko se je v sedemdesetih letih minulega stoletja iskal učinkovitejši nadomestek za zbirnik, sta onkraj velike luže Brian Kernigan in Dennis Ritchie izumila C, z nekoliko drugačnimi motivi pa je v slavnem švicarskem inštitutu ETH Niklaus Wirth utemeljil pascal.

Načrtovanje po pogodbi

Čeprav je pascal skladenjsko čist, lepo definiran in ob visoki zmogljivosti tudi varen, se razen v izobraževalnih ustanovah ni nikoli zares prijel. No, zanimivi primerki uporabe pascala so slavni program za stavljenje zapletenih besedil TeX, velik kos izvirnega operacijskega sistema za prvi Apple Macintosh ter seveda Tetris. Pascalovo preživetje dolgujemo še enemu Evropejcu, Andersu Hejlsbergu, ki je napisal precej uporabnejši Turbo Pascal, ki je bil temelj danes zelo priljubljenega Delphija. Hejlsberg je pozneje prestopil v Microsoft in razvil programski jezik C#. Kljub priljubljenim narečjem so lepe značilnosti pascala večinoma ostajale v senci nadvse uspešnega Cja, ki je doživel največjo slavo kot orodje, v katerem sta Ken Thompson in Ritchie razvila Unix, operacijski sistem, ki še danes ni za staro šaro. Pred programerji pa so se znašli novi izzivi.

Kakovost?

Programska oprema je v minulih desetletjih postala ena najpomembnejših vej industrije. Razvoj prilagodljivih elektronskih komponent je omogočil programski nadzor številnih izdelkov. Žal pa kakovost programske kode ni na ravni, ki jo zahtevajo današnji zapleteni sistemi. Virusi in črvi, ki nadlegujejo najbolj priljubljen operacijski sistem, so le nazoren prikaz slabe kakovosti programja, take in drugačne težave lahko najdemo praktično povsod, kjer je vpletena programska oprema. Od raket, ki jih je treba uničiti po izstrelitvi zaradi programske napake, do avtomobilov, ki obstanejo na cesti, čeprav ni z njihovim motorjem prav nič narobe. Da niti ne omenjamo večjih programerskih projektov, ki skoraj nikoli niso končani pravočasno, s predvidenimi sredstvi in v predvideni funkcionalnosti.

Strokovnjaki se strinjajo, da bo mogoče programsko opremo preobraziti le s posnemanjem drugih zrelih industrijskih panog. Njihova poglavitna prednost so standardizirani, preizkušeni gradniki, iz katerih je mogoče hitro in zanesljivo zgraditi bolj zapletene celote. Pristopi za doseganje tega cilja pa so silno različni. Njihov skupni imenovalec je predmetno usmerjeno programiranje. Priljubljeni C se je razvil v C++, ki ga je nasledil kot najbolj priljubljeno orodje za razvoj visoko zmogljivih programov. Vendar C++ ni zadosti olajšal življenja programerjem in kakovost njihovih izdelkov se ni prav nič izboljšala. Zato sta ga nasledila java in nedavno C#, ki sta prinesla nekaj svežih zamisli, ki so namenjene predvsem izboljšanju kakovosti kode. Java in C# sta danes v središču pozornosti in imata visoko podporo v industriji. A pred njima je precej tiše nastal eiffel.

Domača stran Eiffel Software, Inc.

Eiffel

Eiffel gradi na tradiciji pascala. Kako tudi ne bi, saj je njegov avtor, Bertrand Meyer, nasledil Wirtha na ETH. Meyer je posvetil svojo kariero raziskavam na - po njegovem mnenju - ključnem polju programskega inženirstva: izgradnji zaupanja vrednih gradnikov. Ti gradniki so trajno uporabni elementi programske opreme, katerih kakovost je zajamčena. Tudi znameniti pariški stolp ne bi mogel nastati in še danes navduševati turistov, če ne bi bilo preizkušenih, vnovič uporabnih gradnikov - kovic. Kar poltretji milijon jih je bilo treba za spajanje jeklene konstrukcije. Meyerjev eiffel je nastal na podlagi spoznanj iz njegovega nadvse vplivnega dela, knjige Object-Oriented Software Construction, ki natančno analizira problematiko pisanja kakovostne kode (še vplivnejša je druga izdaja omenjene knjige, ki je izšla leta 1997 pri založbi Prentice Hall, ISBN 0-13-629155-4). Meyer je iskal način, ki bi omogočil učinkovito programiranje v danih orodjih in ob tem prišel do sklepa, da bo cilj lahko dosegel edino s povsem novim pristopom. Tako je ustanovil podjetje Interactive Software Engineering (ISE), danes preimenovano v Eiffel Software, ki je že leta 1985 predstavilo novo metodologijo razvoja programske opreme.

Eiffel je namreč več kot programski jezik (kar je danes kar nekako v navadi, poglejmo samo javo in ogrodje .net). Osrednji del Eiffla je celotna metodologija razvoja programske opreme, ki jo lahko opišemo s posebnim programskim jezikom. Sestavni del eiffla je tudi razvojno okolje, ki je danes na voljo v dveh različicah - od podlage neodvisnem EiffelStudiu in ogrodju .net namenjenem EiffelENViSioNu. Orodji sta za neprofitne namene na voljo brezplačno. Specifikacija Eiffla in temeljne knjižnice so bile pod nadzorom neprofitne organizacije NICE (Non-profit International Consortium for Eiffel), januarja 2002 pa je Meyerjevo podjetje ponudilo eiffel v standardizacijo organizaciji ECMA. Dodatno varnost neodvisnim razvijalcem ponuja prosta različica prevajalnika za eiffel SmartEiffel, ki je skupaj z izvirno kodo na voljo z dovoljenjem GPL in hitro napreduje.

Razvojno okolje EiffelStudio je na voljo za več podlag. Za neprofitne namene ga lahko brezplačno prenesemo s spletnih strani podjetja Eiffel Software, http://www.eiffel.com/.

Programski jezik je tako le orodje, s katerim je mogoče uveljaviti posebno metodologijo razvoja programske kode. Prva značilnost Eifflove metodologije je podpora celotnemu življenjskemu ciklu kode. Ne potrebujemo posebnih orodij za analizo, modeliranje, kodiranje, preizkušanje ali dokumentiranje. Vse je podprto že v samem eifflu. Kljub široki zasnovi eiffel ohranja čisto in preprosto skladnjo, na žalost nekaterih precej bolj podobno pascalu kakor Cju, vendar zelo praktično za svoj namen. Cilj avtorja je bila izrazno močna, a kljub temu preprosta in široko razumljiva koda, ki ni namenjena le programerjem, temveč vsem vpletenim v proces razvoja. Seveda je eiffel tudi popolnoma predmetno usmerjen. Meyer je s podrobno analizo predmetno usmerjenega programiranja našel svojevrstno rešitev, ki jo uteleša jezik. Celotna programska koda je vsebovana v razredih (class) in popolnoma vsi podatkovni tipi so takšni razredi, enakovredni vsem drugim. V eiffelu lahko brez težav dedujemo temeljni podatkovni tip, npr. INTEGER, in na njegovih temeljih izdelamo nov podatkovni tip.

Po vzoru pascala je eiffel strogo tipiziran jezik in omogoča tipsko varno rabo razredov skozi generično programiranje; ta zmožnost je pri javi in C# šele v povojih. Presenečenje je podpora večkratnemu dedovanju (multiple inheritance), tehnika predmetnega programiranja, ki je bila razglašena za problematično in je npr. java ne podpira. Eiffel omogoča učinkovito in varno uporabo večkratnega dedovanja, saj je ta ključna za učinkovito vnovično uporabo že napisane kode, kar je eden izmed postulatov Meyerjeve vizije. Najpomembnejša prednost rabe eiffela pa je mehanizem načrtovanja "po pogodbi" (design by contract, DbC), ki omogoča razvoj zanesljive kode. DbC je najprepričljivejša prednost eiffela, ki so jo mnogi (neuspešno) poizkušali presaditi v druga razvojna okolja. Še vedno pa je le eiffel tisti, ki ponuja vse prednosti DbC in s tem potrjuje pravilnost odločitve po povsem novem programskem jeziku. Še ena zanimiva lastnost eiffela je podpora preoblaganju operatorjev (operator overloading, še ene problematične programerske tehnike, sodeč po javi), preoblaganja metod pa eiffel ne podpira.

Programski jezik je načrtovan tako, da za doseganje zanesljivosti čim bolj onemogoča prosto izražanje. Namesto tega sili v čisto in elegantno kodiranje. Namenoma je izrazno omejen in s tem onemogoča programerju, da je "preveč pameten". Veliko resnice se skriva v znani izjavi, da je največ grehov v računalništvu posledica prezgodnje optimizacije. Tako ali tako je za veliko večino problemov optimizacijo najbolje prepustiti računalniku. Eiffel, kjer je le mogoče, prelaga delo z ramen programerja na stroj, ki lahko isto nalogo opravi bolj zanesljivo. Omejenost Eiffla seveda marsikateremu programerju ne ustreza, še posebej na Cju vzgojenim "kavbojem", ki so jim ljubše hitre in umazane rešitve. Verjetno pa se lahko strinjamo, da tak pristop preprosto ne daje potrebnih rezultatov. Eifflove omejitve obstajajo z namenom omogočiti programerju, da se osredotoči na srž problema, in omogočajo zapis njegove rešitve v obliki, ki je široko razumljiva. Kakovost kode je cilj, ki mu je podrejeno vse drugo.

Vse to nas lahko zapelje v napačen sklep, da je eiffel morda res zanesljiv, a je gotovo neučinkovit. Še posebej po bolečih prvih izkušnjah z javo. Vendar ni tako. Prevajalnik za eiffel namreč izdela kodo v - presenečenje! - ANSI Cju. Ta se zatem z optimizacijskim prevajalnikom prevede v strojno kodo izbrane podlage. Različice eiffla lahko izdelajo še kodo v MS IL (vmesni jezik ogrodja .net) ali celo javansko vmesno kodo. Kakorkoli že, končni izdelek je visoko učinkovita koda, zato nas ne sme presenetiti, da eiffel priporočajo celo za razvoj gonilnikov strojne opreme.

Eiffel omogoča pisanje zanesljive kode, ki je tudi učinkovita. Izdelek prevajalnika je namreč lahko koda v ANSI C, ki jo sodoben prevajalnik zanj lahko dodatno izpili. S tem dobimo neodvisnost od podlage na ravni izvirne kode in visoko učinkovitost prevedenega programa. Eiffel Studio za Okna vsebuje celo Borlandov prevajalnik, ki ga namesti v naš sistem, če je treba.

Programski jezik

Metodologija razvoja po Eifflu zahteva tudi natančno izrazoslovje. Koda se vedno piše kot del razreda (class). Razred sestavljajo zmožnosti (features), ki so lahko lastnosti (attribute) ali rutine (routine). Slednje se delijo na funkcije (function), ki vračajo vrednost, in procedure, ki opravijo zaokroženo opravilo in ne vračajo izida.

Eiffel ne razlikuje velikosti znakov, vendar ponuja jasne napotke, kako poimenujemo posamezne elemente kode. Imena razredov se zapišejo s samimi velikimi znaki, imena spremenljivk in podprogramov le z malimi, konstante pa z veliko začetnico. Če je v imenu več besed, jih ločujemo s podčrtajem (_).

Eiffel zahteva predpisan vrstni red programskih stavkov znotraj razreda. Jezik je tudi strog pri uporabi izrazov in stavkov. Izraz ne more biti stavek in tudi nasprotno ni mogoče. Tako se lahko klic funkcije uporabi edino v izrazu, klic procedure pa je lahko le programski stavek. Ta značilnost strogega ločevanja funkcijskih in pravih podprogramov je ključna prvina Eifflove metodologije, ločevanje ukaza in poizvedbe (Command and Query Separation, CQS). CQS zahteva, da funkcija ne spremeni stanja predmeta, saj sicer ni mogoče napisati zanesljivih testov (sam postopek testiranja bi lahko spremenil stanje predmeta). Po drugi stani procedura spreminja stanje, a ne vrača nobene vrednosti.

Zanimivost eiffla je tudi priporočilo za prikaz programskih izpisov. Za razliko od velike večine jezikov, ki so berljivi le v pisavah, kjer so vse črke enako široke, se za kodo eiffla priporoča sorazmerna pisava. Ključne besede naj bi bile označene krepko, simbolična imena pa ležeče. Komentarji v Eifflu se začno z dvema pomišljajema in presledkom (-- ) in končajo s koncem vrstice. Komentarji, zapisani neposredno po napovedi razreda ali zmožnosti, so hkrati njena dokumentacija.

Oglejmo si klasičen predstavitveni program "Pozdravljen, svet!" v Eifflu:

class HELLO_WORLD

-- Pozdravimo svet
creation make

-- creation našteva imena metod,

-- ki vzpostavijo nov predmet

-- ("konstruktorje")
feature
make is
do
print ("Pozdravljen, svet!%N")
end
end

Preprosta skladnja

Eiffel pozna le šest vrst izvedljivih stavkov:

stvaritev predmeta

prirejanje

klic procedure

pogojni stavek

ponovitveni stavek

izbira

Ponovitveni stavek (loop) v Eifflu je posebej zanimiv, saj ne ponuja samodejnega števca ali zančnega stavka, temveč je treba celotno zanko določiti ročno, kot npr.:

from i := 0 until i >= 10 loop

polje_stevec.put (0, i)

i := i + 1

end

Za obe meji in korak števca i smo morali poskrbeti z ustreznimi programskimi stavki. Zgornji zgled ponazarja tudi posebnost pri uporabi polj, konkretno polja polje_stevec. Jezik nima posebnih skladenjskih mehanizmov za dostop do njegovih prvin (npr. para oglatih oklepajev, []), temveč so polja zgolj izvodi vgrajenega podatkovnega tipa ARRAY, ki ga kot vse druge tipe/razrede upravljamo z rutinami, kot je npr. put(). Eiffel tudi ne pozna ukazov za predčasno prekinitev izvajanja zanke.

Razredi

Za malo boljšo predstavo o tem, kako je videti koda v eifflu, si oglejmo anatomijo uporabnega razreda:

class RACUN

feature

-- Javni vmesnik razreda

znesek: INTEGER

lastnik: OSEBA

limit: INTEGER is 1000

open (kdo: OSEBA) is

-- Določi lastnika računa na kdo.

do

lastnik := kdo

end

polozi (z: INTEGER) is

-- Položi z na račun.

do

pristej (z)

end

dvigni (z: INTEGER) is

-- Dvigni z z računa.

do

pristej (-z)

end

lahko_dvigne (z: INTEGER): BOOLEAN is

-- Je mogoče dvigniti znesek z?

do

Result := (znesek >= z + limit)

end

feature {NONE}

-- Zasebni del razreda

pristej (z: INTEGER) is

-- Dodaj z k znesku.

do

znesek := znesek + z

end

end

Vsak razred se začne z rezerviranko class. Znotraj razreda je lahko poljubno število zmožnosti, ki se začno z rezerviranko feature. Komentar, ki sledi, je nujni del dokumentacije in naj bi opisoval namen posameznih zmožnosti. Prevajalnik ga sicer ne izsili, vendar naj bi ga vsebovali vsi razredi. Kot vemo, so zmožnosti lahko lastnosti, ki jih opišemo s simboličnim imenom in podatkovnim tipom, če želimo, pa tudi z začetno vrednostjo (kot limit). Če vrednosti ne predpišemo, izvajalni sistem jamči vzpostavitev začetne vrednosti (0 za številske tipe, neresnico za logični tip itn.). Zmožnosti pa so tudi rutine. Za razliko od lastnosti imajo blok is ... do ... end. Procedure ločimo od funkcij po tem, da prve nimajo predpisanega podatkovnega tipa, ki ga vračajo, medtem ko ga zadnje imajo, vrnjeni izid pa priredijo navidezni spremenljivki Result. Funkcije ne smejo spreminjati stanja predmeta, čeprav eiffel tega ne izsili za vsako ceno.

Vsak seznam zmožnosti lahko pospremimo s seznamom razredov, ki ga smejo uporabljati. Spodnji seznam efektivno določa zasebno metodo, saj je na seznamu le razred {NONE}, ki je vgrajeni razred brez kakršnihkoli izvodov. Do procedure pristej() imajo tako lahko dostop le druge rutine razreda RACUN in nihče drug.

Vrstni red zmožnosti in njihovih prvin znotraj razreda ni pomemben in ga lahko oblikujemo po lastnih potrebah.

Posebnosti razredov

Posebnosti eiffla se nadaljujejo tudi pri predmetnem programiranju. Za razliko od večine predmetnih jezikov, a v skladu z njihovo starosto, smalltalkom, eiffel ne dovoli dostopa do stanja drugih predmetov! Stavki lahko neposredno spreminjajo le vrednosti lastnega stanja ali krajevnih spremenljivk rutine, vsi dostopi do zunanjega sveta pa morajo biti izvedeni s klici funkcij ali procedur.

Zunanji svet po drugi strani ne ločuje med različnimi zmožnostmi razreda. Za vse zmožnosti pravimo, da se kličejo, čeprav so morda le lastnosti. Na koncu koncev iz stavka:

predmet_a := predmet_b.zmoznost

ne moremo razbrati, ali je zmoznost klic funkcije ali branje lastnosti predmeta predmet_b. To je navsezadnje za uporabnika razreda popolnoma nepomembno, saj gre za podrobnost izvedbe (implementation detail), ki zadeva samo programerja, ki je napisal kodo za razred, ki mu pripada predmet_b.

Ključna lastnost predmetnih programskih jezikov, ki omogoča vnovično rabo že napisane kode, je dedovanje. Kot smo že spoznali, eiffel ne omogoča neposrednega dostopa do stanja drugih predmetov, kar velja tudi pri dedovanju. Tudi izpeljani razredi ne morejo neposredno uporabljati podrobnosti svojih predhodnikov. Le ta značilnost omogoča zanesljivo vnovično uporabo kode: dane razrede moramo uporabiti, ne da bi vplivali na njihov notranji ustroj ali celo spreminjali njihovo kodo. Vnovična uporaba ne pomeni "kopiraj-prilepi-malo popravi".

Tak pristop k dedovanju naravno pripelje do upoštevanja pomembnega pravila pisanja učinkovite kode: uporabi sestavljanje namesto dedovanja, če ne gre za razmerje "je posebni primer" ("is-a"). Če imamo npr. razred BICIKEL, bi ga povsem naravno z dedovanjem izpeljali iz nadrazreda VOZILO, saj je BICIKEL poseben primer VOZILA, ki pač ohranja skupne značilnosti vseh vozil in dodaja nekaj svojih. Po drugi strani ZRAČNICA ni poseben primer BICIKLA, temveč njegov sestavni del, torej zadosti razmerju "ima" ("has a"). BICIKEL torej ima ZRAČNICO, zato jo bomo vključili med njegove lastnosti. S tem imamo na voljo popoln nadzor nad zmožnostmi ZRAČNICE, ki jih želimo izkoristiti, nismo pa v ničemer podvrženi posebnostim dedovanja.

Ker z dedovanjem ne moremo vplivati na podrobnosti nadrazredov, odpade tudi večina slabosti večkratnega dedovanja, kot ga poznajo (ali ne dopuščajo) drugi programski jeziki. Eiffel je eno redkih, če ne edino orodje, ki večkratno dedovanje celo vzpodbuja, brez škode za zanesljivost.

Načrtovanje po pogodbi

Moč eiffla se izkaže pri njegovi podpori za celoten življenjski cikel kode. Z eifflom je mogoče kodo modelirati, saj lahko zapišemo le temeljne značilnosti razreda, brez dejanske izvedbe, lahko celo kombiniramo izdelane in zgolj opisane zmožnosti znotraj istega razreda. Najbolj prepričljiva sposobnost jezika pa je vgrajena podpora načrtovanju po pogodbi (DbC).

DbC temelji na dveh preprostih predpostavkah:

  • Za vsako rutino velja:
  • Preden se začne rutina izvajati, DbC zagotavlja, da so izpolnjeni vsi pogoji za njeno pravilno delovanje.
  • Ko se rutina izteče, DbC zagotavlja, da je dejansko opravila to, čemur je namenjena.
  • Za vsak izvod razreda (predmet) velja:
  • V vseh kritičnih trenutkih nam DbC zagotavlja, da je vsak izvod v veljavnem stanju.
  • Čeprav te predpostavke zvenijo preprosto, so povsem dovolj, da lahko jamčimo za kakovost naših gradnikov. Ključ je torej v natančnem opisu vstopnih pogojev in delovanja rutin ali, z drugo besedo, v specifikaciji. A kako zapisati specifikacijo, da bo omogočala DbC? Gotovo ne v naravnem jeziku, saj je lahko dvoumen, poln nepotrebnih dodatkov in preprosto težko prevedljiv v programsko kodo. Druga možnost je povsem matematičen pristop, ki pa ima težavo, da zna postati bolj zapleten od same rešitve in nerazumljiv ljudem, ki nimajo potrebne podlage v diskretni algebri. Težava večine specifikacij se skriva še v eni pomembni podrobnosti: tipično so ločene od programske kode. Ker pa se koda med reševanjem problema spreminja tudi tako zelo, da je treba specifikacijo prilagajati, nastane problem usklajenosti obeh.

    Eiffel te težave elegantno rešuje po svoje. Sestavni del programske kode vsake rutine so lahko pogoji, ki morajo biti resnični, preden se rutina lahko izvaja, in pogoji, ki morajo biti resnični po tem, ko rutina konča svoje delo. Specifikacija tako postane del programske kode.

    Oglejmo si preprost zgled. Denimo, da želimo z razredom opisati poljuben čas dneva do sekunde natančno. Razred naj ponuja tudi metodo, ki primerja dve časovni vrednosti. Za zunanji svet bi bil razred sestavljen iz naslednjih "poizvedb" in "ukazov":

    class URA_DNEVA

    -- poizvedbe, povpraševanje po stanju

    ura: INTEGER

    minute: INTEGER

    sekunde: INTEGER

    je_prej(cas: URA_DNEVA): BOOLEAN

    -- ukazi, spremembe stanja

    nastavi_uro(u: INTEGER)

    nastavi_minute(m: INTEGER)

    nastavi_sekunde(s: INTEGER)

    Pri izvedbi razreda imamo na voljo dvoje. Zasebno stanje lahko opišemo s tremi spremenljivkami, ki neposredno odražajo poizvedbe po uri, minuti in sekundi dneva, vendar nam bo to zapletlo izdelavo funkcije je_prej(), v kateri moramo primerjati dve uri dneva. Druga možnost je shranjevanje ure v eni sami številki, ki lahko hrani npr. število sekund, ki je minilo od polnoči. Funkcija je_prej() s tem postane trivialno preprosta, se pa zapletejo poizvedbe po posameznih elementih ure, ki jih moramo izračunati iz sekund.

    Denimo, da se odločimo za prvo možnost. Naša naloga je, da stanje predmetov ohranjamo v veljavnem stanju. Če bi metodo za nastavitev ure zapisali tako:

    nastavi_uro(u: INTEGER) is

    -- nastavi uro na u.

    do

    ura := u

    end

    ...kličemo težave. Uporabnik razreda seveda lahko zapiše nekaj takega:

    cas_kosila: CAS_DNEVA

    ...

    cas_kosila.nastavi_uro(26)

    Predmet se bo znašel v nepravilnem stanju in če je del bolj zapletenega sistema, ga lahko v celoti zamaje ali celo zruši.

    Eiffel nam omogoča, da se nepravilni rabi metode izognemo s tem, da jo opremimo s specifikacijo pravilnega delovanja:

    nastavi_uro(u: INTEGER) is

    -- nastavi uro na u.

    require

    veljavna_ura: 0 <= u <= 23

    do

    ura := u

    ensure

    ura_nastavljena: ura = u

    minute_nespremenjene: minute = old minute

    sekunde_nespremenjene: sekunde = old sekunde

    end

    Rutini smo dodali dva nova elementa, require vsebuje seznam pogojev, ki bodo omogočili pravilno delovanje metode, ensure pa vsebuje seznam pogojev, ki jim mora metoda zadostiti po tem, ko se njeno izvajanje konča. Vsak pogoj lahko opremimo z oznako, ki ji sledi dvopičje, da se nanj laže sklicujemo. Uvodni pogoj je jasen: ura je lahko zgolj v veljavnih mejah, nekaj razlage pa zahtevajo končni pogoji.

    Najprej si oglejmo zadnja dva pogoja. Pravilno delujoča metoda mora opraviti natančno to, kar od nje pričakujemo, in nič več. Ne sme imeti neželenih stranskih učinkov in to smo povzeli v dveh pogojih. Stanje minute in sekunde se po koncu izvajanja ne sme razlikovati od stanja pred izvajanjem metode, na katerega se lahko sklicujemo s pomočjo rezerviranke old. Prvi pogoj se zdi odveč. Če smo v izvedbi metode nastavili stanje ure na posredovani parameter u, potem bo seveda tako tudi po koncu izvajanja.

    Stvari postanejo bolj jasne, če se spomnimo, da DbC zahteva specifikacijo pravilnega delovanja, s podrobnostmi izvedbe pa se ne ukvarja. Kaj če bi stanje razreda namesto s tremi spremenljivkami opisali z eno samo, ki hrani sekunde, pretekle od polnoči? Za zunanji svet se seveda ne sme nič spremeniti, torej morajo poizvedbe nenadoma izračunati ure, minute in sekunde iz ene same vrednosti. Torej se v ničemer ne spremeni tudi specifikacija:

    nastavi_uro(u: INTEGER) is

    -- nastavi uro na u.

    require

    veljavna_ura: 0 <= u <= 23

    do

    -- nekako izračunaj novo vrednost in jo shrani v stanje

    sekunde_od_polnoci = ...

    ensure

    ura_nastavljena: ura = u

    minute_nespremenjene: minute = old minute

    sekunde_nespremenjene: sekunde = old sekunde

    end

    Natančno to je bistvo DbC: pogodba je sklenjena med uporabnikom (zunanji razredi) in ponudnikom storitve (našim razredom). Pogodba zagotavlja pravilno delovanje vsake posamezne metode in zagotavlja, da ne bo stranskih učinkov. Z drugimi besedami je specifikacija hkrati tudi testni primer, ki določa, ali je izvedba napisana tako, da zagotavlja izpolnitev pogodbe in s tem pravilno delovanje sistema, v katerega je razred vključen.

    Vgrajena zanesljivost

    S tem kratkim pregledom smo seveda le popraskali po površini tega nadvse zanimivega programerskega orodja, ki združuje preprosto skladnjo, učinkovite mehanizme za pisanje zanesljive kode, podporo za celoten življenjski cikel kode in visoko učinkovitost, saj se izvirna koda s pomočjo optimizacijskih prevajalnikov prevaja v strojno kodo poljubne podlage, za katero obstaja prevajalnik ANSI C, posebne različice eiffla prevajajo celo v vmesno kodo za podlagi .net ali java. Zaradi te značilnosti je eiffel tudi zelo odprt za sodelovanje z zunanjimi gradniki. Omogoča nam celo, da že izdelano kodo, razvito v drugem jeziku, objamemo z njegovimi značilnimi mehanizmi in izpostavimo kot zanesljivejši gradnik.

    Ne, ni šala. Tvorci eiffla ga priporočajo tudi za pisanje gonilnikov strojnih naprav in trdoživih, z učinki bogatih igric.

    Ravno zanesljivost, ki jo eiffel omogoča, je njegova največja prednost. Njegovi avtorji si želijo, da bi sčasoma postal neviden - programerji, ki s pridom uporabljajo njegove prednosti, namreč kmalu spoznajo, da omogoča zelo naravno pisanje kode, ki poganja zapletene sisteme, v katerih med seboj sodeluje veliko število gradnikov. V takih sistemih lahko nezanesljivo delovanje enega samega člena prinese nepredvidljive posledice, to pa žal na lastni koži preverjamo skoraj vsak dan.

    Viri in dodatna literatura:

  • Eiffel Software, Inc., http://www.eiffel.com/
  • SmartEiffel, http://smarteiffel.loria.fr/
  • Linux Journal #14, Introduction to Eiffel, http://www.linuxjournal.com/article.php?sid=1077
  • Bertrand Meyer, domača stran, http://www2.inf.ethz.ch/personal/meyer/
  • Naroči se na redna tedenska ali mesečna obvestila o novih prispevkih na naši spletni strani!
    Prijava

    ph

    Komentirajo lahko le prijavljeni uporabniki