Cílem následujícího textu je seznámení s principy programovacího jazyka BETA, jeho nejdůležitějšími a nejzajímavějšími rysy a také s jeho syntaxí.
Prostřednictvím postupného seznamování se se syntaxí jazyka a za pomoci četných příkladů praktického využití jeho jednotlivých rysů bychom měli postupně dospět k poznání hlavních principů, které jsou samy o sobě tím nejdůležitějším. Tato cesta se může zdát za určitých okolností poněkud zdlouhavá, a proto lze na jejím konci najít relativně ucelené shrnutí základních principů BETAshrnuti.
Jak jinak začít, než pozdravením:

Pomocí popisovače objektu je možno definovat vzor (pattern), jež je základním stavebním kamenem jazyka BETA. Vzor představuje zobecněný abstrakční mechanismus, který je jedním z nejvýznačnějších rysů jazyka BETA (a proto byl také termín vzor zaveden, pro odlišení abstrakčního mechanismu jazyka BETA od typových struktur v jiných jazycích). Vzor v sobě skrývá zobecnění konstrukcí známých jako třída, procedura, funkce, korutina, proces a výjimka.
Předpokládejme nyní následující definici:

Vzor integer, se kterým jsme se již setkali, patří mezi jednoduché typy, tzv. základní vzory (basic patterns). Jsou to:
V BETĚ jsou pro základní vzory definovány relační operátory =, <>, <, >, <=, >= s obvyklým významem. Pro objekty boolean platí, že false je menší (a nikoli rovno) než true. Pro objekty char platí relace dle ASCII.
Instance základních vzorů jsou implicitně inicializovány. Počáteční hodnota pro integer respektive real je 0, pro boolean false a pro char znak null. Pomocí základních vzorů lze deklarovat pouze statické odkazy (proměnné), což je výjimka z důvodu optimalizace generovaného kódu. Jiná možnost, o které se dozvíme dále, totiž dynamická proměnná (odkaz), vyžaduje použití objektů se všemi náležitostmi a tudíž i režií. Tyto jsou definovány v základní knihovně betaenv pod jmény integerObject, realObject, atd.
Vzor odpovídající jednoduché datové struktuře (jako např. record v Pascalu)
může vypadat takto:
![]()
statickou deklaraci jeho instance (objeku vytvořeného dle vzoru planeta),
lze provést například:
![]()
Nyní lze přistupovat k jednotlivým atributům pomocí vzdáleného přístupu
prostřednictvím tečkové notace např.:
![]()
Předpokládejme nyní, že Země je jedinečný objekt, s jedinečnými vlastnostmi,
a popišme jej například takto:

Takovémuto objektu budeme říkat singulární objekt (singular object).
Strukturu objektu takto přímo definujeme popisovačem objektu.
V případě, že potřebujeme definovat objekt, který je jediný svého druhu, není třeba zavádět třídu (vzor), tak jako je tomu ve většině jiných programovacích jazyků (koncept singulárních objektů je podobný mechanismu anonymních typů známých z jazyka Pascal). Možnost zavádění takovýchto beztřídních (class-less) objektů je jedním z důležitých rysů jazyka BETA, neboť má značný význam z hlediska analýzy a návrhu programového systému.
Tak jako jsme se již několikrát setkali se statickým odkazem (zde například atribut zeme je statickým odkazem na příslušný objekt), tak existuje také dynamický odkaz (dynamic reference).
Statický odkaz odkazuje na stále stejný objekt, je tedy jakýmsi konstantním ukazatelem. Instance příslušného vzoru (zde planeta) je vytvořena během vytváření objektu, který obsahuje statický odkaz jako svůj atribut. Takto vytvořený objekt se nazývá statický objekt (static object) nebo také part-object, což vyjadřuje, že je součástí objektu jež obsahuje jeho deklaraci. Statické objekty jsou důležité pro modelování hierarchií typu celek-část.
Stejně tak je nutné mít možnost modelovat situace, kdy objekt obsahuje odkazy
na jiné objekty, které nejsou jeho součástí, jakož i případy, kdy jedna reference
může odkazovat postupně na různé objekty. Tyto požadavky mohou být splněny
prostřednictvím dynamického odkazu.
Deklarace dynamického odkazu:
![]()
satelit je jméno dynamického odkazu a planeta jméno vzoru, který
dynamický odkaz kvalifikuje (typuje), což znamená, že satelit může
odkazovat pouze na instance vzoru planeta (nebo jeho podvzorů - více
viz příslušná kapitola podvzory). BETA je typový jazyk, její reference jsou takto
typovány a díky tomu může být mnoho chyb v přiřazování referencí na objekty
zachyceno již při překladu.
Nyní lze provést například přiřazení pomocí operátoru [] (jež vyjadřuje
získání odkazu na objekt a jeho význam a použití je popsáno v následujícím
textu):
![]()
které přiřadí odkazu satelit odkaz na (statický) objekt zeme,
což znamená, že objekt označený zeme bude nyní dostupný také pod označením
satelit.
Stejně tak lze přiřazovat dynamické odkazy mezi sebou
![]()
přičemž pak zeme, satelit i odkaz označují stejný objekt.
Počáteční hodnota dynamického odkazu je NONE, což znamená odkaz na nic.
Takovýto prázdný odkaz lze vytvořit také explicitně:
![]()
přičemž jeho následné použití pro přístup k nějakému objektu, například
![]()
způsobí chybu za běhu programu (pokud odkaz není NONE, je zajištěno již
při překladu, že odkazuje na objekt mající příslušný atribut a tudíž nemůže
dojít k chybě).
V jazyce BETA je možno za běhu vytvářet nové objekty. Napíšeme-li
![]()
znamená to, že se má vytvořit nový objekt (to vyjadřuje operátor &)
jako instance
vzoru planeta a odkaz na něj (vyjádřeno operátorem []) přiřadit do dynamické
proměnné odkaz.
Je důležité pochopit rozdíl mezi &P a &P[], kde P je
nějaký vzor. První případ říká vytvoř instanci P a spust ji,
zatímco druhý vytvoř instanci P (bez spuštění) a vrať odkaz na ni.
Rozdíl mezi odkazem a hodnotou z hlediska přiřazování si ukážeme na následujícím
příkladu:
Mějme definovány
![]()
a dynamické odkazy ukazující na dynamické objekty (díky provedení následujících
příkazů)
![]()
pak přiřazení
![]()
provede přiřazení stavů objektů dle příslušných vstupních a výstupních částí
(v případě, že by vzor objekt obsahoval také výkonnou část, pak také spuštění
těchto objektů), zatímco
![]()
pouze přiřadí odkaz z dynamické proměnné a do b, čímž budou obě
odkazovat na jeden objekt. V tomto případě (pokud nebyl odkaz na objekt odkazovaný
prostřednictvím b zachován ještě jinde) bude jeden z dynamicky vytvořených
objektů nepřístupný. O uvolnění jemu vyhrazené paměti se v případě potřeby
za běhu programu postará čistič paměti (garbage collector).
V této souvislosti bývá užitečné použití singulárních objektů.
Mějme deklaraci:
![]()
kde object je nejvyšší vzor, zastřešující všechny možné vzory --
více viz kapitola o podvzorech. Dále mějme singulární dynamický objekt reprezentující
posloupnost akcí, který bude vygenerován, ale nikoli spuštěn a odkaz na něj umístěn
do proměnné akce.
![]()
pak příkazem
![]()
lze tento objekt spustit.
Vzor je definován popisovačem objektu, který má obecně tuto strukturu:
(# <deklarace>
enter <seznam>
do <příkazy>
exit <seznam>
#)
Nejprve je seznam deklarací atributů -- odkazů a vzorů (proměnných a typů v obecnější terminologii), pak vstupní část, uvozená identifikátorem enter, se seznamem vstupních parametrů, výkonná část, uvozená identifikátorem do, obsahující posloupnost příkazů a výstupní část, uvozená identifikátorem exit se seznamem výstupních parametrů, tak jak jsme si již ukázali dříve. Všechny části jsou nepovinné.
Jednotlivé deklarace a stejně tak i příkazy se oddělují pomocí středníku. Seznam proměnných se uvádí v kulatých závorkách (pokud je v takovém seznamu jen jeden prvek, lze závorky vypustit) a jednotlivé proměnné se oddělují čárkou.
V kapitole o podvzorech podvzory se dozvíme, že popisovač objektu může mít ještě prefix.
Podmíněný příkaz v jazyce BETA umožňuje podmínku s více alternativami a jeho obecná syntaxe vypadá takto:
(if <výraz1>
// <výraz2> then <příkazy>
// <výraz3> then <příkazy>
...
else
<příkazy>
if)
Symbol // vyjadřuje rovnost. Větev then (řádka uvozená symbolem
//) může být jedna nebo více.
Nejdříve se vyhodnotí výraz1 a výsledek se porovnává s výsledky výrazů
uvedených v jednotlivých then větvích. Jestliže platí rovnost ve více
případech, vybere se libovolná ze splněných větví a provedou se příslušné příkazy. Pokud
neplatí rovnost v žádném případě, spustí se příkazy z větve else, pokud
existuje, neboť ta je nepovinná.
Příklad použití:

Takto lze jednoduše zpracovávat příkazovou řádku programu.
Slouží k tomu vzory definované v základní knihovně betaenv,
noOfArguments, který vrací počet parametrů na příkazové řádce (včetně názvu programu)
a arguments, pomocí něhož lze tyto parametry získat (parametr číslo jedna
je název programu). Pokud je program spuštěn s jedním parametrem, vypíše se
příslušný text následovaný zadaným parametrem, pokud je spuštěn se dvěma
parametry, vypíše se o tom zpráva. V jiných případech (bez parametru, více
než dva parametry) se použije větev else. Vzor putText má stejnou
funkci jako putLine (výpis textu na obrazovku), ale nepřidává ukončení
řádky.
Rozhodnutí na základě logické hodnoty lze provést například takto (případ
false může být ekvivalentně řešen pomocí větve else):

Zajímavější je použití pro větvení na základě několika logických výrazů, například:

V BETĚ existuje ještě jednoduchá varianta podmíněného příkazu (simple if) odpovídající podmíněnému příkazu, tak jak se vyskytuje v jiných programovacích jazycích. Syntaxe je:
(if <výraz> then
<příkazy>
else
<příkazy>
if)
kde výraz musí nabývat logické hodnoty. Větev else je nepovinná. Příklad
použití:

Tento příklad využívá vzoru directory definovaného ve stejnojmenné
knihovně. Přiřazením textu do atributu name objektu vytvořeného podle
tohoto vzoru zadáme cestu k adresáři, který nás zajímá a pak pomocí atributu
empty můžeme zjistit, zda tento adresář obsahuje nějaké položky.
Poznamenejme, že u tohoto příkladu dojde v případě neexistence zkoumaného
adresáře k vyvolání implicitní výjimky (kterou bychom mohli snadno předefinovat),
která ukončí provádění programu vypsáním chybového hlášení.
Použití (běžného) podmíněného příkazu by vyžadovalo přidání // true na konec výrazu v podmínce.
Řídící struktura pro iterace se v BETĚ nazývá příkaz for (for imperative) a má následující strukturu:
(for <proměnná>:<výraz> repeat <příkazy> for)
kde proměnná je název řídící proměnné cyklu, která je viditelná pouze uvnitř cyklu, nelze jí přiřazovat a je typu integer. Nejprve je vyhodnocen výraz, který určuje kolikrát jsou spuštěny příkazy, přičemž řídící proměnná cyklu se postupně zvyšuje o jedničku počínaje hodnotou 1.
Jednoduchý příklad, který sečte všechna čísla od 1 do 1000:

Pokud nepotřebujeme řídící proměnnou cyklu, lze použít jednoduchý cyklus for,
který má stejnou syntaxi, pouze je vypuštěna proměnná a dvojtečka. Pak jsou
prostě příkazy provedeny tolikrát, kolikrát udává výraz. Tedy například:

vypíše desetkrát ahoj.
Důležitá je v tomto kontextu myšlenka, že většina nejrůznějších řídících struktur (jako například cyklus for s určením spodní hranice řídící proměnné, apod.) může být vytvořena pomocí vzorů (tak jak tomu skutečně v základních knihovnách je a jak ještě uvidíme) a proto má BETA předdefinováno jen několik málo řídících struktur.
Návěští může být přiřazeno příkazu takto:
jméno: <příkaz>
Návěští jméno je dostupné pouze uvnitř pojmenované konstrukce.
Vykonávání pojmenovaného příkazu (může to být popisovač objektu obsahující skupinu příkazů) může být ukončeno pomocí příkazů leave nebo restart. První z nich, leave, způsobí skok za konec příkazu, jehož jméno je uvedeno za příkazem leave. Naopak vykonání příkazu restart způsobí znovuzapočetí vykonávání příslušného (jménem za příkazem restart daného) příkazu. Příklad použití těchto příkazů si ponecháme až na kapitolu o podvzorech podvzory.
Datová struktura podobná polím v ostatních programovacích jazycích se
v BETĚ nazývá repetition. Tento termín byl zvolen pro odlišení od jiných
programovacích jazyků, neboť datový typ repetition v sobě zahrnuje kromě
konceptu pole (lineární posloupnost prvků téhož typu) také jisté operace
(především pro dynamickou změnu velikosti datové struktury). Proto bude
nadále používán jako český ekvivalent termínu repetition termín repetice.
Deklarace
![]()
kde R je jméno repetice statických odkazů prvků popsaných vzorem P,
které má velikost 10 prvků (na místě konstanty 10 může být libovolný výraz typu
integer). Jednotlivé prvky lze odkazovat takto
![]()
kde R.range je atribut, který má každá datová struktura repetice
a pomocí kterého lze získat její velikost (počet prvků). Prvky jsou vždy číslovány
od jedné.
Stejně tak lze deklarovat repetici dynamických odkazů
![]()
kde každý prvek je odkaz na jednu instanci vzoru P. Zde tedy nebudou na rozdíl
od předchozí repetice statických odkazů při jejím vytváření vytvořeny instance
vzoru P, ale jen dynamické odkazy (inicializované na NULL).
Příklad definice vzoru reprezentujícího jednoduchý zásobník pro čísla:

Pro uložení dat v zásobníku slouží repetice Data, proměnná Top
reprezentuje aktuální vrchol zásobníku a vnořené vzory Push a Pop
základní operace se zásobníkem. Využívá se implicitní inicializace proměnné Top
na nulu, díky čemuž není nutno zásobník inicializovat. Postačí jej vytvořit
jako statický odkaz a pak již ho lze používat. V následujícím příkladu

jsou čísla vložená postupně (vzestupně) do zásobníku prvním cyklem druhým
cyklem vybírána v opačném pořadí a tištěna na obrazovku (vzor newLine
provede odřádkování).
Při pokusu o přístup k prvku repetice s indexem mimo rozsah 1 ...\ range dojde k vyvolání standardní výjimky, která ukončí běh programu s chybovým hlášením. To zde nastane, pokud
Datová struktura repetice je pole s dynamicky měnitelnou délkou. Velikost
repetice udávaná při deklaraci se chápe pouze jako počáteční velikost.
Možnost dynamické změny velikosti je důležitá z hlediska použití datové
struktury pro přímou implementaci prostředků pro ukládání dat, neboť
z hlediska analýzy většina takových problémů vede na určité úrovni návrhu
k potřebě dynamicky měnit velikost datových struktur.
Například u našeho příkladu, zásobníku, může být výhodné, pokud při pokusu
o vložení prvku bude zásobník v případě potřeby zvětšen namísto generování
výjimky. Pak bude pro uživatele takového zásobníku zcela lhostejné, jakou
(počáteční) hodnotu velikosti datové struktury zvolil ten, kdo jej implementoval.
Úprava definice zásobníku pro dosažení tohoto výsledku je poměrně jednoduchá
(týká se pouze vzoru Push, jinak se nic nemění):

Každá datová struktura repetice má atribut extend, který slouží ke
zvětšení rozsahu. Pokud máme repetici Data o deseti prvcích
(Data.range=10) a provedeme přiřazení
![]()
pak se rozsah zvýší o přiřazenou hodnotu, tedy na Data.range=15, přičemž hodnoty
prvků Data[1], Data[2], ... Data[10] zůstanou zachovány a nově budou
k dispozici prvky Data[11], Data[12], ... Data[15], které dostanou
počáteční hodnotu nula.
Jinou možností je vytvořit zcela novou datovou strukturu, pomocí atributu
new, například
![]()
vytvoří novou datovou strukturu repetice o rozsahu daném přiřazenou hodnotou
(zde tedy 20 prvků), přičemž původní prvky budou nedosažitelné a nové prvky
dostanou pořáteční hodnotu nula.
Pro datovou strukturu repetice je definováno vzájemné přiřazení. Předpokládejme
deklarace:
![]()
pak přiřazení
![]()
má následující význam:
![]()
tedy obsah repetice je překopírován s tím, že rozsah je náležitě přizpůsoben.
Pro datovou strukturu repetice je definován řez (repetition slice),
pomocí kterého je možno vybrat část prvků repetice. Například
![]()
zkopíruje do R2 pouze ty prvky R1, které mají index 3 až 5. Obecně
přiřazení
![]()
kde e1 a e2 mohou být libovolné výrazy typu integer je
interpretováno jako
![]()
Vzor text slouží k reprezentaci řetězců znaků, neboli posloupnosti objektů
typu char.
Instanci vzoru text může být přiřazována konstanta například takto:

Vzor text nepatří mezi základní vzory, proto může být použit k vytváření
dynamických odkazů a jako nadvzor. Je definován v základní knihovně basiclib
a má poměrně mnoho atributů sloužících k manipulaci s textem (viz [4]).
Programovací jazyk BETA patří do rodiny objektově orientovaných programovacích
jazyků a podobně jako v jiných objektově orientovaných jazycích, tak i v BETĚ
lze vytvářet hierarchie vzorů (pokrývající jako zobecnění hierarchie tříd)
sloužící k reprezentaci klasifikačních hierarchií. V této souvislosti budeme
používat termín podvzor (subpattern) vyjadřující, že se jedná
o vzor, který je specializací jiného vzoru
.
Pro takovýto mechanismus se obvykle
v objektově orientovaných jazycích používá termín dědičnost.
Vzpomeňme si nyní na vzor planeta, který by mohl vypadat takto:

a vezměme vzor hvezda, který by mohl být deklarován takto:
![]()
Takto definované vzory nám mohou sloužit pro reprezentaci příslušných pojmů
a jejich vlastností, ale jak známo z objektově orientovaných metod návrhu
a implementace počítačových systémů (viz například [2]),
je výhodné zavést jistou klasifikační hierarchii těchto vzorů, využívající
a podchycující jejich společné vlastnosti a vzájemné vztahy.
Figure: Znázornění příkladu jednoduché hierarchie vzorů
Za tímto účelem zavedeme zastřešující objekt shrnující společné vlastnosti všech
objektů naší jednoduché hierarchie (viz obr. 1.1):
![]()
Vzor planeta pak lze zavést jako specializaci (podvzor) vzoru teleso:
![]()
Použitím vzoru teleso jako prefixu popisovače objektu pro vzor planeta
dosáhneme toho, že popisovač objektu pro vzor planeta zdědí všechny
atributy vzoru teleso. Takto objekty deklarované jako instance vzoru
planeta budou obsahovat atributy velikost, hmotnost
a atmosfera.
Vzor hvezda deklarujeme takto:
![]()
Vzory planeta a hvezda jsou podvzory vzoru teleso, zatímco
ten je pro ně tzv. nadvzorem (super-pattern) .
Tato terminologie je odrazem pohledu na klasifikační hierarchie z hlediska
jejich významu pro generované instance. Definujeme-li vzor hvezda jako
podvzor vzoru teleso, popisujeme dodatečné vlastnosti, v tomto případě
je to svitivost. Lze řící, že množina všech instancí vzoru hvezda
je podmnožinou množiny všech instancí vzoru těleso. Obecně přidáním nových
vlastností k vlastnostem nadvzoru zmenšíme množinu všech možných instancí podvzoru
a tato množina je podmnožinou množiny všech možných instancí příslušného nadvzoru.
Jak již bylo řečeno dříve, dynamické odkazy v BETĚ jsou typovány (kvalifikovány) na určitý vzor, který určuje množinu objektů, na kterou se lze odkazovat. Z tohoto hlediska mají klasifikační hierarchie značný význam, neboť odkaz typovaný na nějaký nadvzor může odkazovat na libovolný objekt z množiny instancí všech jeho podvzorů.
Vzory jako teleso bývají nazývány abstraktní nadvzory
, což vyjadřuje, že neslouží pro vytváření
instancí, ale pouze jako
nadvzory. Mezi jejich využití patří také vytváření univerzálních odkazů.
Například:
![]()
může odkazovat na libovolnou instanci vzorů planeta a hvezda
(pokud by takové instance existovaly, může samozřejmě odkazovat také na instance
vzoru teleso) a všech jejich případných podvzorů.
Kvalifikace dynamického odkazu také určuje, které atributy mohou být odkazovány
vzdáleným přístupem. Například
![]()
je legální a bude odkazovat na příslušný atribut, ať už R odkazuje na
instanci jakéhokoli podvzoru vzoru teleso, neboť každý takový podvzor
je rozšířením vzoru teleso a obsahuje tudíž zaručeně všechny jeho atributy.
Legální jsou tedy vzdálené přístupy právě k těm atributům, které jsou atributy
vzoru, jímž je příslušná dynamická proměnná kvalifikována.
Mějme nyní deklaraci:
![]()
neboli dynamický odkaz P, který může odkazovat na instance vzoru planeta.
Pak je možné provést přiřazení
![]()
neboť množina objektů, na které může odkazovat P je podmnožinou
množiny objektů, na které může odkazovat R. Zatímco přiřazení
![]()
je možné provést pouze v případě, že R odkazuje instanci, kterou může
odkazovat i P, v našem případě instanci vzoru planeta.
V tomto případě však nelze o legálnosti přiřazení rozhodnout
při překladu. Proto je takovéto přiřazení při překladu pokládáno za správné,
avšak překladač sem umístí kontrolu, která případně způsobí chybu za běhu programu
(tak je zajištěna správnost vzdálených přístupů k atributům, neboť do dynamického
odkazu nelze přiřadit odkaz na objekt, který nemá příslušné atributy).
Testování příslušnosti objektů ke vzorům lze provádět také explicitně. Například
kontrola před přiřazením z minulého odstavce by mohla vypadat takto:

Výraz R## odkazuje na vzor objektu na který ukazuje R a výraz
planeta## znamená vzor planeta (více viz kapitola popisující
vzorové proměnné vzorprom).
Poznamenejme, že test by ve skutečnosti vypadal spíše
R## <= planeta##
, neboť obecně lze přiřazovat do
proměnné P odkazy nejen na instance vzoru na který je kvalifikována,
ale i všech jeho podvzorů.
Analogicky výše uvedeným informacím o singulárních objektech lze definovat
singulární objekt také pomocí popisovače objektu s prefixem, tj. s využitím
specializace:
![]()
Zeme takto má všechny vlastnosti společné planetám a jednu, život, navíc.
O vzoru object jsme se již také zmínili: je to nejobecnější abstraktní nadvzor. Navíc, vzor object je také implicitní nadvzor všech vzorů, které nemají nadvzor definován, neboli pokud uvedeme popisovač objektu bez prefixu, je to interpretováno jako popisovač objektu s prefixem object. Takto jsou všechny vzory podvzory vzoru object.
Výkonná část vzorů může být také děděna a specializována od nadvzorů
k podvzorům.
Mějme
![]()
kde příkaz inner P1 slouží k řízení specializace akcí mechanismem uspořádaného
přidávání dalších akcí -- určuje místo, do kterého bude umístěn kód případných
podvzorů specializujících vzor P1. Pro instance vzoru P1 má tedy
příkaz inner P1 prázdný význam. Avšak vzor
![]()
takto definuje pro svoje instance výkonnou část odpovídající
![]()
neboli výkonná část byla zděděna z nadvzoru a na místo definované v nadvzoru
příkazem inner přidány akce z výkonné části příslušného vzoru. Obecně
vykonávání akcí instance určitého vzoru začíná ve výkonné části jeho nejvyššího
nadvzoru (vzato do důsledku, je to vždy vzor object, který obsahuje ve
své výkonné části pouze příkaz inner) a postupně (v místech určených umístěním
příkazu inner) přechází do výkonných částí jednotlivých podvzorů, až do
daného vzoru a pak stejným způsobem (tentokrát zdola nahoru) vykonává zbytky
jednotlivých výkonných částí (uvedené za jednotlivými příkazy inner).
Běžně se používá zkrácená verze příkazu inner, prostě bez uvedení vzoru, což znamená, že se týká bezprostředně obklopujícího popisovače objektu.
Se způsobem dědění a rozšiřování atributů objektů od nadvzorů k podvzorům jsme se již seznámili. V této souvislosti však je třeba ještě říci, že všechny atributy deklarované v nějakém vzoru jsou viditelné ve všech jeho podvzorech.
Mechanismus specializace akcí se dá v kombinaci se singulárními objekty
použít pro vytváření řídících struktur.
Nejjednodušší příklad, který nám zároveň ukáže použití příkazů leave
a restart, je tento:
![]()
Vzor cycle lze jako nekonečnou smyčku (singulární objekt reprezentující
nekonečnou smyčku) použít jednoduše takto:
![]()
Takovou smyčku lze opustit příkazem leave cycle.
Je jasné, že uvnitř popisovače objektu popisujícího singulární objekt nemá příkaz inner smysl, neboť takový popisovač objektu nemůže mít podvzor, který by dal příkazu inner smysl.
Častým využitím výše naznačené techniky jsou mnohé iterátory definované v různých
datových strukturách. V tuto chvíli uveďme jednoduchý příklad, který vypíše
obsah adresáře pomocí atributu scanEntries vzoru directory (se
kterým jsme se již setkali):

Objekt vytvořený podle vzoru scanEntries prochází postupně všechny položky
příslušného adresáře, odkaz na ně přichystá do proměnné s určitým názvem
a strukturou (found, více viz [4]), načež provede příkaz
inner, neboli spustí příkazy uvedené v popisovači singulárního objektu,
jež je jeho potomkem.
Mnoho dalších případů využití singulárních výkonných objektů lze najít v knihovně containers (viz [7]), kde jsou definovány základní datové struktury jako například zásobník, fronta, seznam, tabulka s rozptýlenými hesly (hash), .... Ve složitějších případech se často využívají vlastnosti virtuálních vzorů o kterých pojednává samostatná kapitola virtvzory, ve které lze také nalézt další příklady použití.
Mějme:
![]()
pak vzor P2 má vstupní část (a,b,c) a výstupní část (z,x,y),
neboli vstupní část je spojením vstupní části nadvzoru a vstupní části příslušného
vzoru. Totéž platí o výstupních částech.
Pomocí podvzorů je možno popisovat vlastnosti a strukturu objektů specializací tohoto popisu z jiných vzorů (nadvzorů). Pomocí virtuálních vzorů (virtual patterns) je možno popsat obecné vlastnosti určitého atributu v nadvzoru a tento popis specializovat v podvzorech.
Předpokládejme, že potřebujeme pro vzory v naší hierarchii těles definovat
atributy popisující akci vytiskni na obrazovku informace, které jsou
o příslušném objektu k dispozici.
Bez nároků na propracování detailů zobrazení lze zavést následující definice:

kde je dosaženo požadované funkce, neboť každý ze vzorů teleso, planeta,
hvezda má atribut tisk vypisující příslušné informace, přičemž
pokud zavedeme například odkaz
![]()
pak provedení
![]()
vykonná příslušnou činnost v závislosti na tom, kterého vzoru je instancí objekt
jež R právě odkazuje. Způsob, jakým je toho dosaženo popisují následující
poznámky:
V základní knihovně betaenv je definována následující řídící struktura:

která by se dala považovat za zobecnění řídících konstrukcí while
a repeat, jak jsou známy z jiných jazyků.
V tomto příkladu je také vidět ještě jednu možnost kvalifikace virtuálního vzoru, totiž formou P (# ... #), neboli popisovačem objektu specializujícím nějaký vzor P. Nám již známá možnost, přímá kvalifikace pomocí popisovače objektu, je vlastně speciální případ, kdy implicitně P = object.
Uvedenou řídící strukturu lze jednoduše používat, například takto

Vraťme se nyní k definici datové struktury zásobník a pokusme se definovat
(generický) zásobník, který umožní vytvářet zásobníky objektů libovolného
typu:

Virtuální vzor element určuje typ objektů, které lze ukládat do zásobníku.
Protože je kvalifikován vzorem object, může být prvkem zásobníku instance
libovolného vzoru. Mezi operace zásobníku byla přidána (pro zásobník zcela
netypická) operace ForAll, která dovoluje procházet všechny objekty uložené
v zásobníku a provádět s nimi nějaké operace. Tento mechanismus je často využíván
v knihovnách pro operace iterativního charakteru, příkladem může být operace
scanEntries vzoru directory jež byla použita v předcházejícím textu.
V podvzorech vzoru stack můžeme upřesnit typ prvků, které budou ukládány
do zásobníku. Definujeme například zásobník pro instance vzoru hvezda:
![]()
pak do zásobníku hvezdy lze vkládat pouze objekty vzoru hvezda
nebo jeho podvzorů. Pak také lze napsat:
![]()
pro vypsání všech dostupných informací o všech objektech uložených v zásobníku.
Protože atribut Current je kvalifikován virtuálním vzorem element,
který v objektu hvezdy znamená vzor hvezda, lze přistupovat
k atributu tisk.
Vzor Stack by mohl být kořenem hierarchie vzorů pro zásobníky různých typů objektů, což by bylo výhodné například pro postupné zavádění dalších operací nad zásobníkem tak, jak se specializují vlastnosti potenciálně ukládatelných objektů.
Vezměme nyní příkaz &P. Jak jsme se již dozvěděli, tímto příkazem se vytvoří
a spustí nová instance vzoru pojmenovaného P. Pokud je P deklarováno
jako definice vzoru
![]()
pak je jednoznačně určeno, jaký vzor se pod názvem P skrývá. Pokud je
P deklarováno jako definice virtuálního vzoru, například
![]()
pak může P znamenat různé vzory (omezené však na podvzory vzoru R)
podle toho, jak je P rozšiřováno v podvzorech vzoru T.
Navíc, v jazyce BETA, je k dispozici mechanismus zvaný vzorová proměnná (pattern variable) pro vytváření proměnných, které mohou odkazovat na různé vzory, jež jim mohou být přiřazovány za běhu programu.
Deklarací
![]()
definujeme vzorovou proměnnou S kvalifikovanou vzorem P.
Vzorové proměnné mohou být přiřazovány libovolné vzory (nikoli instance), které
jsou podvzory vzoru P (nebo sám P).
Máme-li podvzory
![]()
pak
![]()
přiřadí vzor P1 do vzorové proměnné S. Příkaz &S potom
vytvoří a spustí instanci vzoru P1, ale provedeme-li
![]()
pak &S vytvoří a spustí instanci vzoru P2.
V jazyce BETA je pro libovolný objekt možné získat odkaz na jeho strukturu, tj.
na strukturu podle níž byl vytvořen. Pokud se nejedná o singulární objekt, získáme
takto odkaz na vzor, jehož je objekt instancí. Odkaz na strukturu získáme
![]()
kde R je odkaz na objekt.
Mějme
![]()
pak R1## je vzor P (odkaz na vzor P lze jinak získat zápisem
P##), R2## je struktura P(# ... #) a R3## je
odkaz na příslušnou strukturu, podle toho na jaký objekt R3 právě odkazuje.
Pro vzorové proměnné jsou definovány relační operace. Například

Prostřednictvím vzorových proměnných lze se vzory provádět tytéž operace jako s hodnotami jiných typů, lze je přiřazovat proměnným, předávat jako parametry procedurám či vracet jako hodnoty funkcí.
Pomocí vzorových proměnných je možno měnit chování objektů za běhu programu.
Použijeme-li vzorovou proměnnou jako atribut nějakého vzoru, lze dosáhnout
různé funkce tohoto atributu v různých instancích vzoru a dokonce tento atribut
zcela předefinovat.
Například:

má každá instance vzoru T atribut S jinak specializován (může se
jednat i o plné předefinování, neboť P může být object).
Za běhu programu lze dále libovolně měnit chování objektů, například takto:
![]()
Má-li být programovací jazyk vhodný pro vytváření použitelných a udržovatelných netriviálních aplikací, musí být k dispozici mechanismus pro rozdělení zdrojových textů na menší části, moduly. Toto tvrzení je nepochybně dostatečně známé, případně několik dobrých důvodů pro ně lze najít například v [1] na straně 261.
Pro programovací jazyk BETA byl pro popis modularizace vyvinut a použit tzv.
jazyk fragmentů
(fragment language), nikoli
však jako součást jazyka BETA. Jazyk fragmentů popisuje strukturu programu, zatímco
jazyk BETA popisuje strukturu a činnost procesu tímto programem definovaného.
Navíc jazyk fragmentů je nezávislý na jazyce BETA a principiálně by mohl být
použit spolu s většinou programovacích jazyků.
Základní myšlenkou jazyka fragmentů je využití gramatiky jazyka (BETA): Libovolná větná forma (sekvence terminálních a neterminálních symbolů definovaných gramatikou) může být modulem. Nejjednodušším případem je program složený z jednoho modulu, který obsahuje pouze terminální symboly. Modularizaci zavedeme tak, že v textu ponecháme některé neterminální symboly a větné formy popisující jejich expanzi umístíme do jiných modulů. Způsob složení takto definovaných větných forem do kompletního programu popisuje jazyk fragmentů.
V této souvislosti je důležitý formální zápis bezkontextové gramatiky jazyka
BETA, jež je uveden například v [3] v příloze B
.
Jazykem fragmentů je nutno popsat všechna místa ve větné formě, kde se nacházejí
neterminální symboly, jež je třeba expandovat pomocí jiných modulů (větných
forem). Takovému místu říkejme štěrbina (slot).
Protože v každé větné formě se může vyskytovat libovolný počet neterminálních
symbolů stejné syntaktické kategorie, každý neterminální symbol musí mít přiřazen
jedinečný název.
Zápis neterminálního symbolu (definice štěrbiny) vypadá takto:
![]()
kde SLOT je klíčové slovo, T jméno štěrbiny a A syntaktická
kategorie příslušného neterminálního symbolu (odpovídá názvu neterminálního
symbolu).
Vzpomeňme nyní definici zásobníku z kapitoly 1.4 a definujme

kde jsou namísto výkonných částí operací uvedeny štěrbiny. Jména štěrbin patří
do jiného jmenného prostoru, než ostatní jména (náleží jinému jazyku). Jméno
štěrbiny musí být unikátní vzhledem k celému programu.
Větné formy je také třeba jednoznačně identifikovat, aby bylo jasné, které
štěrbině náleží. Zaveďmě pojem fragment , označující
strukturu definovanou jako:
![]()
kde F je název fragmentu, A syntaktická kategorie a větná
forma je vlastní obsah fragmentu. Ta může obsahovat další neterminální
symboly (štěrbiny).
Fragmenty lze organizovat do skupin, což je výhodné pro logicky provázané fragmenty
sloužící společnému účelu. Každá skupina fragmentů má svoje jméno
a obsahuje příslušné fragmenty prostě uvedeny za sebou v libovolném pořadí.
Skupina fragmentů je (nikoli obecně) realizována formou jednoho souboru
v souborovém systému a identifikována jménem tohoto souboru.
Mějme například soubor stackbody.bet obsahující:

neboli definující skupinu fragmentů. Klauzule ORIGIN určuje
skupinu fragmentů, která bude použita pro přiřazování fragmentů štěrbinám.
Specifikuje, že fragmenty Push a Pop budou substituovány za odpovídající
štěrbiny v souboru stack
, který takové štěrbiny musí obsahovat.
Jak jsme již naznačili, první příklad uvedený na začátku kapitoly by měl obsahovat
navíc jisté náležitosti:

Základní prostředí (nebo také základní knihovna), definující základní standardní vzory a zajišťující
inicializaci a ukončení běhu programu se nazývá betaenv. Je uloženo
v souboru, jehož jméno je udáno v příkazu ORIGIN výše uvedeného
příkladu
a vypadá asi takto:

zkombinováním těchto fragmentů na základě příkazu ORIGIN dojde k dosazení
fragmentu PROGRAM za příslušnou štěrbinu v základní knihovně (neboli
každý program musí definovat fragment se jménem PROGRAM syntaktické kategorie
popisovač objektu popisující jeho strukturu). Výsledek
bude vypadat takto:

Standardní vzory uvedené v základní knihovně budou přístupné z fragmentu
PROGRAM, neboť v něm jsou takto viditelná všechna jména, která jsou viditelná
z místa, kde byla uvedena štěrbina PROGRAM.
Štěrbina LIB slouží pro vytváření knihoven ve smyslu souboru obecněji
použitelných vzorů (za PROGRAM lze dosadit jeden popisovač objektu, za
LIB seznam deklarací vzorů).
Knihovnu vytvoříme například takto (pojmenujme ji knihovna):

Námi definované vzory jsou substituovány za štěrbinu LIB do základní
knihovny, jsou viditelné pro štěrbinu PROGRAM a jsou jim přístupná
všechna jména viditelná v místě štěrbiny LIB. Tento výsledný text však
není program, neboť štěrbina PROGRAM zůstala bez expanze.
Pro smysluplné využití knihovny budeme potřebovat příkaz INCLUDE, který
umožňuje kombinování několika fragmentů do jednoho:

Takto lze vzory definované ve fragmentu LIB používat ve fragmentu
PROGRAM. Příkaz INCLUDE určuje, že skupina fragmentů
knihovna se stane logickou součástí souboru v němž je uveden. Proto
budou nalezeny příslušné fragmenty pro štěrbiny LIB i PROGRAM.
Skupina fragmentů může obsahovat více než jeden příkaz INCLUDE.
Při vytváření modulů je nutné mít možnost přesně specifikovat rozhraní pro ostatní
moduly a oddělit ho od vlastní implemetace modulu. K tomuto účelu slouží
příkaz BODY .
Ten uvádí skupinu fragmentů, kterou je ještě potřeba
k nalezení expanze pro všechny štěrbiny aktuální skupiny fragmentů, ale která není
součástí tohoto fragmentu, tudíž není viditelná tam, kde je viditelný tento
fragment. Vraťme se k našemu zásobníku. Doplníme-li jeho definici takto:

jedná se o příklad definice rozhraní. Pomocí příkazu BODY je definována
skupina fragmentů, která určuje implementaci zásobníku. Proměnné používané
v implementaci zásobníku byly skryty zavedením atributu Private který
je obsahuje (implementace musí být samozřejmě příslušně upravena, aby tyto proměnné
odkazovala plným jménem, např. Private.Top)
.
Příkazů BODY může být ve skupině fragmentů více.
V literatuře [1] lze najít diskuzi použití jazyka fragmentů pro podporu programových variant a různých implementací modulů. Podrobnější informace lze najít tamtéž. Problematika modularizace s ohledem na použití příkazu inner je diskutována v [3], kap. 6.2.
Implementace ( BETA System) systému fragmentů je poněkud méně obecná než je patrno z výše uvedeného nástinu principů: Syntaktické kategorie pro štěrbiny jsou omezeny na DoPart, ObjectDescriptor a Attributes. Jména souborů (skupin fragmentů) a odkazů na ně mají jistá omezení. Skupiny fragmentů mohou mít zadány vlastnosti, což jsou příkazy složící například pro řízení překladu a spojování generovaného kódu. Podrobnější informace lze získat především v [3] kapitola 6.
Zajímavým aspektem jazyka BETA je také obecná bloková struktura. Rozšiřuje
vyjadřovací schopnost jazyka a dovoluje i značně specifické vyjadřovací
konstrukce.
Z rozsahových důvodů zde uveďme pouze jeden jednoduchý příklad pro ilustraci. Mějme
vzor
![]()
a instance
![]()
pak a.X i b.X jsou vzory, ale každý jiný. Použijeme-li tyto vzory
pro vytvoření instancí, budou to instance navzájem různých vzorů. Více viz
[1], kapitola 8.
Programovací jazyk BETA vychází z tradice jazyka Simula. Jedním z důležitých vlastností inspirovaných touto tradicí je systém založený na korutinách pro realizaci modelování konkurenčních aktivit. Více viz [1], kapitoly 13-15 a [2].
Součástí vývoje implementace jazyka BETA () je také podpora pro zajištění persistence objektů, o které lze získat informace v [2] kapitola 12 a v [11]. Další oblastí, na kterou je zaměřen vývoj, je podpora pro vytváření distribuovaných aplikací. O současném stavu knihoven pro distribuci objektů pojednává [12].
V předcházejícím textu jsme se několikrát setkali s pojmem výjimka. Realizace podpory výjimek v jazyce BETA je popsána v [1], kapitola 16.
Důležitou součástí jazyka BETA je filozofie programování, uvedená například
v [1], kapitola 18. Mnoho dalších informací lze získat, kromě
studia doporučené literatury, také v elektronické podobě. Vhodný startovní
bod je domovská stránka jazyka BETA na http://www.daimi.aau.dk/
beta.
Programovací jazyk BETA patří mezi moderní objektově orientované jazyky. Byl vyvinut v simulovské tradici skandinávskou školou objektově orientovaného programování. Je však menší a výrazově schopnější než Simula. Jeho základní charakteristikou je mocný a jednotný abstrakční mechanismus zahrnující koncepty třídy, procedury, funkce, korutiny, procesu a výjimky. Základní stavební kámen jazyka BETA, představující tento abstrakční mechanismus, se nazývá vzor.
Podle vzorů se vytvářejí objekty (instance), které mohou za běhu programu vznikat a zanikat. Programovací jazyk BETA je spjat s používáním automatického čištění paměti.
Každý vzor se skládá z atributů, které reprezentují jeho části, či odkazy na jiné objekty. Stejně tak může obsahovat lexikálně vnořené definice jiných vzorů. Dále může každý vzor definovat svoji výkonnou část a prvky, jejichž hodnoty jsou předávány před respektive po spuštění objektu. Objekty BETY mohou mít funkci korutin, čímž je umožněno modelování alternujících sekvenčních procesů a procesů kvaziparalelních.
Vzory jsou uspořádány do hierarchie dědičnosti. Každý vzor definuje svůj nadvzor, jehož je specializací prostřednictvím definice dalších vlastností. Specializace výkonných částí je provedena mechanismem, kdy kód uvedený ve vzoru je umístěn do kódu nadvzoru na místo jednoznačně určené nadvzorem. Vzory mohou být virtuální a navíc BETA zavádí pojem vzorové proměnné, která umožňuje pohled na vzory jako na hodnoty, jež lze předávat jako parametry jiným vzorům a zacházet s nimi jako s běžnými hodnotami a tak umožnit například měnit dynamicky chování objektu.
Dále je pro jazyk BETA charakteristický silný typový systém a obecná bloková struktura. Z hlediska identifikace objektů je důležitá možnost vytváření objektů bez nutnosti zavádět vzor, což je výhodné pro případ, kdy existuje pouze jeden objekt svého druhu.
V souvislosti s jazykem BETA byl vyvinut prostředek pro zajištění modularizace nazvaný jazykem fragmentů. Základní myšlenkou jazyka fragmentů je využití gramatiky jazyka (BETA): Libovolná větná forma (sekvence terminálních a neterminálních symbolů definovaných gramatikou) může být modulem.