Od “strojáku” k OOP
MIROSLAV VIRIUS, časopis CHIP
Programátorské řemeslo patří určitě k nejmladším, přesto už má za sebou docela pohnutou historii. V právě zahajovaném miniseriálu si zavzpomínáme, jak to všechno začínalo, pokračovalo a k jak neuvěřitelně mocným nástrojům nakonec dospělo.
První počítače v dnešním smyslu slova spatřily světlo světa přibližně před padesáti lety. I když základní princip zůstal stejný, změnilo se skoro vše od samotných počítačů až po terminologii, a tak se nelze divit, že se změny nevyhnuly ani programování.
Myšlenka stará 180 let
Vývoj programování je neodmyslitelně spojen s vývojem výpočetní techniky, tedy především počítačů. Asi prvním významným pokusem o takovéto zařízení byla Difference Engine, jejíž zjednodušený funkční prototyp sestrojil Angličan Charles Babbage už v r. 1822. Šlo o zařízení pro výpočet a tisk hodnot polynomů. Při dalším vývoji tohoto zařízení dospěl r. 1837 ve spolupráci s matematičkou Adou Augustou Lovelanceovou k zařízení, které nazval Analytical En
gine a které lze již označit za univerzální číslicový počítač se vstupní, výstupní a operační jednotkou. Tento počítač měl být poháněn parním strojem (!) a řízen programem zapsaným na děrných štítcích. Babbage svůj “analytický stroj” nikdy nedokončil, mj. i proto, že nebyly k dispozici dostatečně kvalitní materiály pro tak komplikované zařízení; o čtvrt století později však úspěšně realizoval podobný, ale jednodušší projekt Švéd George Scheutz. Součástí návrhu analytického stroje musela samozřejmě být i propracovaná sada instrukcí. Je zajímavé, že na rozdíl od prvních elektrických počítačů, sestrojených o sto let později již obsahovala mj. podmíněný skok. V minulém století však byla myšlenka automatického počítacího stroje lidem natolik cizí, že nenašla výraznější odezvu ani ve vědeckých kruzích. Ještě ve známé knize Camilla Flammariona “Konec světa”, vydané r. 1893, počítají astronomové z 25. století dráhu komety tři dny a tři noci, samozřejmě ručně. (Flammarion sám byl jedním z význačných astronomů své doby a málokdo numericky počítá více než právě astronomové.) Přitom v té době už existoval např. Hollerithův děrnoštítkový počítací stroj, vyvinutý v r. 1888 a velice úspěšně využitý při sčítání lidu v USA roku 1890. Myšlenka elektronických počítačů dozrála těsně před druhou světovou válkou. V Německu si dal takovéto zařízení patentovat Konrad Zuse roku 1936, nezávisle na něm postavil podobné zařízení r. 1939 v USA John Atanasoff. Je zajímavé, že instrukční sady Zuseových počítačů neobsahovaly podmíněné skoky Zuse zřejmě neznal Babbageovy práce. Další podobná zařízení byla za druhé světové války zkonstruována i ve Velké Británii; měla sloužit především k automatickému řízení protiletadlových zbraní. Tyto stroje se od dnešních počítačů lišily v jednom základním ohledu: programovaly se zpravidla propojováním funkčních bloků nebo mačkáním tlačítek. S myšlenkou, že program (neboli instrukce řídící chod počítače) jsou vlastně také data a lze je uložit do operační paměti (a tedy i měnit), přišel roku 1944 John von Neumann prvním strojem tohoto typu byl EDSAC, postavený v r. 1949. Nebudeme daleko od pravdy, prohlásíme-li, že na principu počítačů se od té doby nic podstatného nezměnilo. Počítač má stále centrální jednotku, operační paměť a nějaká vstupní a výstupní zařízení. Co se ale výrazně změnilo, je výkonnost, cena a způsob využití počítačů. Uvádí se, že za posledních 50 let klesla cena počítačů o více než 5 řádů, tedy více než stotisíckrát. Přitom v podobném poměru narostla jejich výkonnost. První počítače se používaly pouze k vědecko-technickým nebo vojenským výpočtům dnes je najdeme prakticky všude neznat alespoň základy práce s počítačem je skoro jako neumět číst a psát.První abstrakce: asembler
Vraťme se ale k našemu hlavnímu tématu, k programování. Chceme-li program (rovnocenný ostatním datům) uložit do paměti počítače, musí být zapsán pomocí jednoduchých, elementárních instrukcí a ty musí být vyjádřeny čísly. Tyto instrukce v počátcích programování stejně jako dnes vyjadřují nejjednodušší operac
e, které počítač umí, tedy přesuny jednotlivých datových položek, základní aritmetické operace s uloženými čísly atd. Pokud jste si někdy zkusili programovat ve strojním kódu, víte, v čem je největší problém: všechny adresy v takovém programu jsou absolutní. To znamená, že po téměř jakémkoli zásahu do programu se změní adresy mnoha instrukcí a proměnných a že programátor pak musí projít celý program a upravit všechny odkazy na ně. Není třeba zdůrazňovat, jak snadno lze přitom udělat chybu. Vedle toho musí programátor užívající strojní kód znát čísla vyjadřující jednotlivé instrukce a architekturu počítače, a to velmi podrobně. Obojí se samozřejmě počítač od počítače liší. Nelze se tedy divit, že se od počátku 50. let začaly objevovat první asemblery, programovací jazyky, které nejen nahradily číselné kódy instrukcí mnemotechnickými zkratkami, ale především zavedly symbolické adresy. Programátor mohl libovolné místo v programu nebo libovolná data pojmenovat (přidělit jim tzv. identifikátor) a dále se na ně prostřednictvím tohoto symbolického jména odvolávat. Tím se neuvěřitelně zjednodušilo nejen psaní, ale především oprava a údržba programů. Nic ovšem není zadarmo – mechanickou přepočítávací “otročinu” musel vzít na svá bedra překladač, program, který ze zápisu v asembleru vytvořil program ve strojním kódu. Zde se poprvé programátor odpoutal od detailů architektury počítače a mohl se při programování daleko více věnovat řešenému problému. S klidným svědomím můžeme tvrdit, že asembler znamenal první vrstvu abstrakce, vloženou mezi programátora a hardware. Brzy měly následovat další. V této době počítačového dávnověku došlo i k první revoluci v organizaci programu: Programátoři začali užívat podprogramy. Jinými slovy, naučili se rozdělovat algoritmus na opakovaně používané části. Spolu s tím se objevily i další novinky, a to oddělený překlad různých částí programu a knihovny podprogramů.Terminologie
To, co dnes běžně označujeme jako asembler, se tehdy většinou nazývalo “jazyk symbolických adres” či “jazyk asembleru”. Pod názvem “asembler” se zpravidla skrýval překladač a někdy i sestavovací program, tedy – řečeno dnešní terminologií – linker. Tento význam slova asembler dnes už nacházíme spíše jen v (nepočítačových) výkladových slovnících.
Vyšší jazyky
Programován
í v asembleru je sice podstatně snazší než programování ve strojním kódu, ale i tak je obtížné, zdlouhavé a stále vyžaduje znalost architektury počítače; je to práce pro specializované odborníky. Přitom vytvořené programy (říkalo se jim strojově orientované) nejsou přenositelné na počítače jiných typů. Proto se velmi brzy objevila myšlenka problémově orientovaného programovacího jazyka, který by byl nezávislý na počítači a ve kterém by např. bylo možno zapisovat výpočty podobně jako v matematice.Revoluce: Fortran
Ve skutečnosti se taková myšlenka objevila ještě dříve než počítače von Neumannova typu – vyslovil ji r. 1945 K. Zuse. Jedním z prvních úspěšných pokusů byl “Operational Compiler”, vytvořený v r. 1954 na M.I.T. (Laning, Zierler). Obchodní úspěch znamenal však až jazyk Fortran, vyvinutý u firmy IBM v letech 1954 – 1957 týmem, který vedl J. Backus. Tento tým si vytkl úkol vyvinout snadno zvládnutelný programovací jazyk, který povede k efektivnímu výslednému programu. S odstupem času lze tvrdit, že s
vého cíle dosáhl – první verzi Fortranu bylo opravdu snadné zvládnout a jeho překladač byl patrně jeden z nejefektivnějších, jaké kdy byly vytvořeny. Obsahoval řadu optimalizačních algoritmů, z nichž některé si dokonce spouštěly úseky přeloženého programu, aby mohly co nejlépe určit alokaci registrů. Tehdejší Fortran obsahoval jen nejnutnější programové konstrukce – jeden druh cyklu (s pevně daným počtem průchodů), jen neúplný podmíněný příkaz, základní číselné typy, pole, příkazy pro vstup a výstup. Umožňoval však používat poměrně složité matematické výrazy – ostatně jeho název, odvozený jako zkratka ze slovního spojení “Formula Translation”, prozrazuje, k čemu byl především určen. Od verze Fortran II bylo možno rozdělit program na několik samostatně překládaných částí. Přestože se velice brzy objevily další jazyky, stal se Fortran na dlouhou dobu nástrojem “skutečných programátorů” a dodnes je v některých oblastech intenzivně využíván. Ovšem v onom roce 1957 znamenalo jeho uvedení opravdu revoluci. Nejenže se ukázalo, že lze navrhnout vyšší programovací jazyk a k němu vytvořit fungující překladač, ale především bylo zpřístupněno programování “běžným” vědcům a inženýrům a tím byl také nepřímo podnícen zájem o použití počítačů v mnoha dalších oblastech. I když byl Fortran určen především pro vědecko-technické výpočty, začali jej záhy programátoři využívat i v dalších oblastech, dokonce i v takových, pro které se v podstatě vůbec nehodil (například i pro “zpracování hromadných dat” – dnes bychom řekli pro jednoduché databázové aplikace).Druhá vrstva
Fortran (a po něm i další vyšší programovací jazyky) vkládá vlastně další vrstvu abstrakce mezi programátora a počítač. Jinými slovy, umožňuje programátorovi vyjadřovat se více v jazyce problému, a tedy soustředit se více na řešenou úlohu a méně se zabývat počítačem. Představuje také výrazný krok směrem k přenositelnosti.
Terminologie
Podíváme-li se do literatury té doby, zjistíme, že v 50. letech a na počátku 60. let “programování” znamenalo strojní kód nebo asembler. O programu ve Fortranu se hovořilo jako o “matematické specifikaci problému” a o překladu jako o “automatickém programování”. Tehdejší programátor tedy sestavil matematickou specifikaci a počítač se podle ní automaticky naprogramoval. Při ladění se chy
by hledaly v matematické specifikaci, nikoli v programu...První konkurence: Algol a Cobol
Ve Fortranu z konce 50. let chyběla řada dnes běžných nástrojů: Nebyl k dispozici složený příkaz, úplný podmíněný příkaz ani cyklus řízený podmínkou. Fortran neumožňoval definovat vlastní datové typy, neobsahoval nástroje pro práci s pamětí, nepodporoval rekurzi; zato obsahoval několik druhů příkazů skoku. Navíc vyžadoval pevnou úpravu zdrojového textu (poplatnou tehdy nejčastějšímu vstupnímu médiu, děrnému štítku) –
prvních pět znaků na řádku bylo vyhrazeno pro návěští, příkazy se zapisovaly od 6. do 72. pozice, každý příkaz musel být na samostatném řádku apod. Běžný zdrojový program ve Fortranu byl tedy sice podstatně přehlednější než běžný zdrojový program v asembleru, ale zcela přehledný zpravidla nebyl. Absence složených příkazů a úplného IF nutila totiž programátory hojně používat příkazy skoku – ono neblaze proslulé GOTO. Jediné logické členění programu představovaly podprogramy. V průběhu času se proto objevila různá doporučení, jak program zapisovat, aby byl přehledný, a byly dokonce vytvořeny nástroje, které takto uměly hotový program upravit. (Jeden z nich se nazýval tuším Olympus.)Velmi brzy ovšem začaly vznikat další jazyky, z nichž se zmíníme o dvou – Algolu 60 a Cobolu. Algol 60 vytvořila společná komise evropské a americké organizace uživatelů počítačů. I když se k praktickému počítání příliš nehodil (neumožňoval překlad programu po částech, neumožňoval pracovat se znaky a znakovými řetězci, obsahoval některé problematické konstrukce, takže nebylo snadné napsat dobrý překladač, nebyl připraven na práci se soubory apod.), velice výrazně ovlivnil další vývoj programovacích jazyků a programování vůbec.
Algol 60 totiž nabídl programátorům mj. složený příkaz, (téměř) úplný podmíněný příkaz, podstatně propracovanější příkaz cyklu atd. Ukázal, že předávat parametry podprogramům lze různými způsoby a jaký to může mít význam. Přinesl také rekurzivní volání podprogramů.
Druhým nepominutelným zjevem mezi programovací
mi jazyky počátku 60. let je Cobol, jazyk pro zpracování hromadných dat vytvořený z podnětu amerického ministerstva obrany. Stojí za zmínku, že jedním z cílů bylo vytvořit jazyk, který bude srozumitelný ekonomům, obchodníkům a vojákům, tedy nikoli jen programátorům a počítačovým specialistům. (Šlo ovšem o to, aby zmínění lidé dokázali program číst, nikoli snad psát. Jinými slovy: cílem Cobolu bylo, aby mohl nadřízený snadno kontrolovat své podřízené – přečíst si, co počítač dělá – a nemusel přitom počítačům rozumět.) Program v Cobolu se proto velice podobá anglickým větám; je rozčleněn do pojmenovaných odstavců a sekcí. První verze dokonce neumožňovala zapisovat běžné aritmetické výrazy, výpočty se zapisovaly “slovně”, příkazy jako ADD A TO B GIVING C. (Tvůrci Cobolu zřejmě neměli valné mínění o úrovni řídících pracovníků...) Dalším problémem, se kterým se Cobol musel vyrovnat, byl přenos programů mezi různými počítači. Americké vládní a armádní instituce totiž podle zákona nesměly preferovat žádného dodavatele, a proto používaly řadu počítačů od nejrůznějších výrobců – problémy s přenositelností programů byly na denním pořádku. Navržené řešení bylo v podstatě jednoduché: v záhlaví programu se v Cobolu specifikuje počítač, na kterém se bude program překládat, a počítač, na kterém poběží. Ovšem překladačů, které by znaly také počítače od jiných výrobců, zase tak moc nebylo... Cobol přinesl (a bohatě využíval) nový datový typ, který se dnes označuje jako záznam nebo struktura – skupinu proměnných různých typů chápanou jako jeden celek. Vzhledem ke své orientaci na zpracování velkého množství dat také nabídl nástroje pro třídění souborů podle dané hierarchie klíčů a prostředky pro popis tiskových sestav. Z programátorského hlediska nebyl Cobol příliš přitažlivý; jeho první verze neobsahovaly např. možnost rozčlenění programu na podprogramy, všechny datové struktury byly globální a programátor je musel deklarovat předem atd. A hlavně – jeho blízkost skutečné angličtině znamenala nepříjemné prodloužení zdrojového textu, a tak si Cobol brzy vysloužil pověst jazyka příliš “ukecaného”. Přesto je to dodnes jeden z nejdůležitějších programovacích jazyků, neboť v něm byly napsány miliony řádků programů, které se dodnes používají.Zrání: další jazyky
První programovací jazyky
ukázaly základní repertoár nástrojů, které jsou v programech obvykle potřeba: Datové typy pro reálná a celá čísla, znakové řetězce, pole, struktury. Výpočet výrazů zapisovaných podle matematických zvyklostí, cykly, větvení programu, vstupní a výstupní operace. Rozčlenění programu na podprogramy a možnost odděleného překladu různých částí programu. Už na počátku 60. let bylo jasné, že jednoúčelové programovací jazyky nepředstavují dokonalé řešení. Nešlo jen o to, že jejich počet rostl závratným tempem – uvádí se, že např. už v r. 1963 bylo ve Velké Británii implementováno přes 30 různých jazyků – ale i o to, že se neustále rozšiřoval prostor pro využití počítačů. Výsledkem byla mj. snaha o vytvoření univerzálního programovacího jazyka a o maximální zefektivnění programátorské práce. Podívejme se alespoň heslovitě na některé další programovací jazyky, které se v následujících letech objevily na scéně, a na jejich přínos:V r. 1960 byl publikován jazyk Lisp, který přivedl na scénu neprocedurální programování. Našel využití např. v oblasti umělé inteligence. V r. 1964 uvedla firma IBM jazyk PL/I, který představoval zřejmě první alespoň trochu úspěšný pokus o univerzální programovací jazyk. Šlo o syntézu Fortranu, Algolu, Cobolu a prvků některých dalších jazyků.
Mezi jiným v něm najdeme nástroje pro práci s pamětí, pro ošetřování výjimečných stavů a pro paralelní zpracování (i když zatím jen pro vstupní a výstupní operace).V témže roce se objevil jazyk Basic (Kemeney, Kurtz), další z programovacích prostředků, které měly být pokud možno srozumitelné i neprofesionálům. Také tento jazyk způsobil revoluci – přinesl totiž první programové prostředí; k tomu se ještě vrátíme. V roce 1967 byl publikován jazyk Simula 67, který uvedl na scénu objektově orientované progra
mování. O rok později se objevil Algol 68. I když by se podle názvu mohlo zdát, že šlo jen o novou verzi, byl to zcela nový jazyk, který přinesl mj. nástroje pro paralelní programování (semafor jako nástroj pro synchronizaci přístupu k systémovým prostředkům, paralelní věta), možnost přetěžování operátorů, prostředky pro řízení alokace proměnných apod. Jeho osud byl však podobný osudu Algolu 60: nedočkal se většího rozšíření, ale myšlenky, které přinesl, ovlivnily snad všechny programovací jazyky, které přišly po něm.Jazyk Pascal (1971) vznikl jako reakce na neuvěřitelnou složitost PL/I a Algolu 68 a byl původně určen především k vyučování informatiky. Jeho uvedení způsobilo takřka přes noc převrat ve výuce programování (a v důsledku toho později i v programátorské praxi), neboť Pascal je jednoduchý, snadno zvládnutelný a přitom poskytuje potřebné základní nástroje. (Standardní Pascal nemá prostředky pro paralelní programování, pro oddělený překlad ani pro ošetřování chyb, tj. pro práci s výjimkami. Tyto nás
troje jsou dnes nezbytné pro skutečné programování, nejsou však zpravidla potřebné v základní výuce informatiky. Standardní Pascal nenabízí ani prostředky pro objektové programování; jejich význam na počátku 70. let ještě nikdo nechápal – nejen programátoři, ale i teoretici mysleli ještě “procedurálně”.) Pascal také nabídl novinku – výčtové typy. Navíc ukázal, že program lze psát přehledně a “čistě”, a přímo k takovému pojetí i vedl. Jazyk C vytvořil D. Ritchie (1972). Céčko nabízí podobné nástroje jako Pascal, navíc možnost odděleného překladu a přístup k některým nízkoúrovňovým konstrukcím (adresová aritmetika a další prostředky).V průběhu 70. byl z podnětu ministerstva obrany USA vyvinut jazyk Ada, který se stal závazným standardem v programech psaných pro tuto instituci. Je navržen s maximálním ohledem na bezpečnost programování. Přinesl několik nových nástrojů; setkáme se zde např. s generickými konstrukcemi (to může být třeba seznam naprogramovaný nezávisle na typu ukládaných hodnot – typ se dosadí až
při použití jako parametr) nebo s randez-vous (jeden z paralelních procesů specifikuje, kdy a za jakých podmínek se setká s druhým procesem).Smalltalk je zřejmě první čistě objektový jazyk – naprosto vše v něm jsou objekty. Byl navržen v 70. letech u firmy Rank Xerox. Nedílnou součástí jeho implementace je i objektové vývojové prostředí. Vývoj tohoto jazyka především výrazně posunul vpřed teorii objektově orientovaného programování.
Na počátku 80. let navrhl B. Stroustrup jazyk C++, z počátku jen jako objektové rozšíření jazyka C, později jako samostatný jazyk, který není s C plně kompatibilní. Mnohé z vlastností C++ byly inspirovány staršími jazyky Algol 68, Ada, Smalltalk a samozřejmě také jazykem C. V C++ se asi poprvé objevily prostory jmen jako nástroj
pro organizaci rozsáhlých programů. Poprvé se tu také setkáváme s propracovaným mechanismem vícenásobné dědičnosti. Novinkou je i automatické volání destruktorů při zániku instance.Čistě objektový jazyk Eiffel publikoval B. Meyer r. 1991. Novinkou v něm je princip kontraktu: v deklaraci metody objektového typu můžeme specifikovat předběžné podmínky (co musí splňovat parametry metody) a podmínky, které musí platit při ukončení metody. Porušení kontraktu způsobí vznik výjimky.
Asi posledním významným jazykem
z devadesátých let je Java (Sun Microsystems, 1995). Je to téměř čistě objektový jazyk, vytvořený vypuštěním řady “potenciálně nebezpečných” nebo neobjektových konstrukcí z C++ a doplněním nástrojů pro paralelní programování, pro ověřování bezpečnosti apod. Jedním ze základních požadavků je naprostá nezávislost na platformě, takže se programy v Javě zpravidla interpretují pomocí tzv. virtuálního stroje. Poznamenejme, že Java znovu uvedla na scénu automatickou správu paměti, tj. garbage collector.Příště
To
lik o nejdůležitějších jazycích, které má dnešní programátor k dispozici. K vytvoření dobrého programu však nestačí mít kvalitní programovací jazyk. Musíme udělat důkladnou analýzu problému, musíme dát dohromady dobrý návrh řešení a toto řešení musíme správně naprogramovat. K tomu nám mohou pomoci další nástroje, ale také dodržování určitých pravidel. O tom si povíme příště.