A BETA programozási nyelv

Példaprogramok



Letölthető példaprogramok:

A szokványos "hello world" Helloworld.bet
Faktoriális számítása rekurzióval Faktorialis.bet
Szorzótábla a for ciklus használatával Ciklus.bet
Négyzetgyök számítása loop ciklussal Negyzetgyok.bet
Tömb elemeinek rendezése és a text használata Quicksort.bet
Referenciák használata Referencia.bet
Példa öröklődésre Oroklodes.bet
Többszörös öröklődés emulálása Tobbszoros.bet
Egy egyszerű verem Stack.bet
Randevú Randi.bet
Párhuzamosság - konkurencia Konkurencia.bet
Kivételkezelés Exception.bet
Dinamikus kötés bemutatása Dinamikus.bet
Külön interfész és implementáció Stack.bet
Stackbody.bet
Stackuser.bet
Lift szimulátor lift.html

Példaprogramok magyarázattal:

1. példa

ORIGIN '~beta/basiclib/betaenv'; INCLUDE '~beta/basiclib/numberio'; ---- program: descriptor ---- (# swap: (# x,y: @integer; enter (x,y) exit (y,x) #); gswap: (# type:< object; x,y: @type; enter (x,y) exit (y,x) #); iswap: gswap (# type::< integerobject; #); fswap: gswap (# type::< realobject; #); rigo: (# size: @integer; color: @integer; name: @text; show:< (# do inner; name[]->putline #); enter (size,color,name) exit (size,color,name) #); pi: (# exit 3.14 #); e: (# exit 2.71 #); rswap: gswap (# type::< rigo; #); a,b: @integer; f,g: @real; r1: @rigo; r2: @rigo (# show:: (# c: @text; enter c do c[]->name.append; #) #); do 15->a; 20->b; (a,b)->iswap->(a,b); 'a = '->puttext; a->putint; 'b = '->puttext; b->putint; newline; pi->f; e->g; (f,g)->fswap->(f,g); 'f = '->puttext; f->putreal; ', g = '->puttext; g->putreal; putline; (5,2,'nadi')->r1; (1,1,'kis')->r2; (r1,r2)->rswap->(r1,r2); 'r1.name = '->puttext; r1.show; 'r2.name = '->puttext; 'rigo'->r2.show; #)

Eredmény:

a = 20, b = 15
f = 2.710000, g = 3.140000
r1.name = kis
r2.name = nadirigo

Magyarázat:

A példa azt mutatja, hogy a többi programozási nyelvben szereplő fogalmak, konstans, változó, eljárás, osztály stb. hogyan valósíthatóak meg mintával, vagyis hogy a mintafogalom mennyire általánosítása ezeknek.

Az első három sor nem BETA nyelven, hanem az ún. fragment-rendszer nyelvén íródott. Ennek a három sornak hasonló a funkciója, mint az #include <stdio.h> sornak C-ben. Az ezek után következő rész már végig, a (#-től a #)-ig BETÁ-ban van. Látszik, hogy egy BETA program egy minta, aminek a do része kerül végrehajtásra. A program speciális minta, mert csak deklarációs, és végrehajtási része van.

A példaprogramban szereplő swap minta a deklarációs részhez tartozik (a program-minta deklarációs részéhez). Ez a swap minta tulajdonképpen egy függvény, ami megcseréli a két argumentumát, úgy hogy nem használ fel erre parancsokat (vagyis nincsen do része a mintának). Ez azért tehető meg, mert BETA-ban a minta több értéket is visszaadhat. Ez a swap minta csak azért szerepel, hogy bevezesse a gswap mintát, ami ennek egy általánosítása. A gswap csak egy kicsit tér el a swap mintától, szerepel benne a type :< object; sor, és a két paramétere nem egész, hanem type típusú. A type :< object; azt jelenti, hogy a type egy virtuális attribútum, ami lehet az object minta, vagy annak részmintája. Az object minta eléréséről az ORIGIN kezdetű sor gondoskodik, az object minta minden mintának a implicit szupermintája, tehát itt a type attribútum tulajdonképpen tetszőleges minta lehet. Ez az egyik szép tulajdonsága a BETA-nak - amit a minta-fogalom bevezetésével nyert -, hogy egy minta tartalmazhat osztály-attribútumokat is. A gswap mintát szupermintaként használva, és a virtuális type attribútumot kiterjesztve egy iswap és egy fswap függvény-mintát példányosítunk a következő két sorban. Az integerobject és a realobject mintákat szintén az ORIGIN sor segítségével érjük el, ezek sem a nyelv alapszavai. Azért van ezekre szükség, mert nem lehet olyat írni, hogy type ::< integer, ugyanis az alaptípusok (integer, char, real, ...) nem minták - hatékonysági okok miatt). Ha megnézzük a program-minta do részét, láthatjuk, hogyan kell meghívni a swap-függvényeket:

(a,b)->iswap->(a,b); (f,g)->fswap->(f,g);

A '->' operátort használja a BETA az értékadásra, és az eljárás-, ill. függvényhívásra is, vagyis ezzel adja át az enter listában szereplő objektumoknak a nyíl bal oldalán szereplő értékeket. Látszik, hogy nincs éles különbség az értékadás és a függvényhívás között.

Többszörös értékadás is lehetséges a BETA-ban, de ez nem szimultán értékadás: az

(a,b)->(b,a);

utasítás az

a->b; b->a;

szekvenciának felel meg.

Az (5, 2, 'nadi') -> r1; utasítás nem értékadás, hanem (jelen esetben) függvényhívásként értelmezhető. Ha a rigo mintának nem lenne enter listája, akkor ugyanez az inicializáló hatás a (5, 2, 'nadi') -> (r1.size, r1.color, r1.name) többszörös értékadással érhető el.

A programban látható példa konstans megvalósítására:

pi : (# exit 3.14 #);

Vagyis a konstans a BETA-ban egy olyan minta, aminek csak visszatérési értéke van.

Tekintsük a programban szereplő legbonyolultabb mintadeklarációt (BETA-ban a deklaráció és a definíció fogalmak keverhetőek - a dokumentáció keveri is -, mert a C-ben megszokott módon nem lehet deklarálni típusleírót (itt mintát), BETA-ban mindig a teljes definíciót meg kell adni.) - ez a rigo minta deklarációja. Eltekintve a minta enter és exit listájától, észrevehető, hogy ez tulajdonképpen egy osztály, ugyanis megvannak az adatattribútumok (size, color, name) és van metódusa is (show, ami ráadásul virtuális). Az enter lista csak a fent említett egyszerűbb inicializálás céljából szerepel. Az exit listának ebben az esetben nincs igazán jelentősége. Az r2 objektum deklarációjánál látható, hogy a virtuálisnak deklarált show metódus akár a példányosítás alkalmával is kiterjeszthető.

2. példa

ORIGIN '~beta/basiclib/betaenv'; INCLUDE '~beta/basiclib/numberio'; ---- program: descriptor ---- (# Point: (# x,y: @integer; show:< (# do x->putint; ','->put; y->putint; inner; newline; #); enter (x,y) #); ThreeDpoint: Point (# z: @integer; show::< (# do ','->put; z->putint; inner #); enter z #); a: ^Point; b: ^ThreeDpoint; do &Point[]->a[]; (10,20)->a; a.show; &ThreeDpoint[]->b[]; (100,200,300)->b; b.show; (* a[]->b[]; - futasi hiba *) (* 13->a.z; - szemantikus hiba: a-nak nincs z attributuma *) b[]->a[]; a.show; #)

Eredmény:

10,20
100,200,300
100,200,300

Magyarázat:

A példában először egy két-, majd egy háromdimenziós pontot leíró mintadeklaráció szerepel. A Point mintának a show virtuális attribútuma - ezt a :< jelöli -, amit a ThreeDpoint minta kiterjeszt. Felmerülhet a kérdés, hogy egy mintát eddig is ki tudtunk terjeszteni, mindenféle virtuális segítség nélkül, miért van tehát szükség virtuális mintára?

A válasz a következő: mintát ki tudunk terjeszteni a belőle származtatott részmintában, de ez a kiterjesztés annyit jelent, hogy új deklarációkat, paramétereket, utasításokat adunk hozzá a már meglévőkhöz. Viszont a már meglévő attribútumokat nem tudjuk így módosítani. Erre való a virtuális minta-attribútum (adatattribútum, metódus, vagy osztály), így megadjuk a lehetőséget, hogy ezt az attribútumot a későbbi származatatás (részminta-képzés) során megváltoztassuk. Ez a megváltoztatás viszont csak kiterjesztés lehet (az fenti módon).

A példában szereplő show eljárást, ha a Point mintában nem virtuális eljárás-mintaként lenne deklarálva, akkor a ThreeDpoint mintában szereplő show eljárás egyszerűen eltakarná, és csak a z értékét írná ki a b.show (persze ha a Point.show nem virtuális, akkor a ThreeDpoint.show deklarációjában ::< helyett :, vagy :< kell, hogy álljon).

3.példa

ORIGIN '~beta/basiclib/betaenv'; ---- program: descriptor ---- (# A: (# do 'A'->put; #); B: (# do 'B'->put; #); C: ##Object; Create: (# type: ##Object; x: ^Object; enter type## do &type[]->x[]; x; #); do A##->Create; B##->Create; A##->C##->Create; C; #)

Eredmény:

ABAA

Magyarázat:

Ez a példa a BETA minta-változójának egy lehetséges felhasználását mutatja. BETA-ban lehet egy mintára implicit módon hivatkozni, egy változón keresztül. A programban szereplő Create függvény paraméterként egy mintát kap, ezt példányosítja, és a példányt aktivizálja.

4.példa

ORIGIN '~beta/basiclib/betaenv'; ---- program: descriptor ---- (# A:@ (# A1: @text; show: (# do A1[]->putline; #); #); B:@ (# B0: @text; B1: (# do 'B1'->A.A1; #); do 'B'->A.A1; #); do 'A'->A.A1; A.show; B; A.show; B.B1; A.show; #)

Magyarázat:

Ez a példa arról szól, hogy a BETA semmiféle korlátozást nem ad egy minta valamely attribútumának elérésére. Megfelelő hivatkozással elérhető olyan adat, akár írás, akár olvasás céljából, aminek elérését hasonló szituációban más nyelvekben korlátozni lehet. BETA-ban, ha egy adott programkörnyezetben az X minta látható, és X1 az X mintának egy attribútuma, akkor X.X1 elérhető abban a pontban. A példában láthatjuk, hogy az A objektummal azonos blokkban, vele egy szinten deklarált B objektum kényelmesen meg tudja változtatni A-nak az A1 belső változóját. Az információ elrejtése az ún. fragment-rendszer segítségével valósítható meg. Az adatrejtés sikere azon múlik, hogy az X.X1 kifejezés szintaktikailag helyes, az X.X1.X11 viszont szintaktikai hibát eredményez. A módszer lényege az, hogy a privát részeket egy blokkal mélyebbre süllyesztjük, és így azok a mintán kívülről már elérhetetlenek lesznek (egyszerűen azért, mert legfeljebb egy pont szerepelhet a hivatkozásban.)

5.példa

A minta sokoldalúságát a következő példán keresztül szemléltetjük:

employee: (# name: @text; birthday : @date; dept: ^Department; totalHours: @integer; registerWork: (# noOfHours: @integer; enter noOfHours do noOfHours+totalHours->totalHours #); computeSalary:< (# salary: @integer; do inner exit salary #); #);

Legyen két alosztály: worker és salesman

worker: employee (# seniority: @integer; computeSalary::< (# do noOfHours*80+seniority*4->salary; inner; 0->totalHours #); #); salesman: employee (# noOfSoldUnits: @integer; computeSalary::< (# do noOfHours*80+noOfSoldUnits*6->salary; 0->noOfSoldUnits->totalHours; inner; #); #);

Magyarázat:

employee: ez egy osztályminta, ahol a name, birthday, dept és totalHours alkotják az adatmezőket, registerWork és computeSalary pedig a függvénymezőket (metódusokat).

registerWork: ez egy nem-virtuális eljárásminta, ami azt jelenti, hogy a tevékenységét teljes egészében megadtuk az employee bázisosztály részeként. Az enter kulcsszó után kell az eljárásminták bemenő paramétereit felsorolni, a do kulcsszó után pedig az utasításokat kell megadni.

computeSalary: ez viszont virtuális eljárásminta, mert csak egy része lett specifikálva az employee bázisosztályon belül. Egy mintát a neve után írt :< jelpárral jelezhetünk virtuálisnak. A példában ez a minta azért lett virtuális, mert a fizetés kiszámítását a dolgozó szerepétől függően kívántuk differenciálni.

Az exit rész után a kimenő paramétereket sorolhatjuk fel. (Az enter és az exit rész opcionális szerepet tölt be az eljárásminták esetén; lehet, hogy mindkettő jelen van, lehet, hogy csak az egyik, és lehet, hogy egyik sem.)

Virtuális minta esetén kötelező az inner kulcsszó megadása a do részben. Az inner azt jelzi, hogy arra a helyre a származtatott osztályban megadott konkrét kódot kell majd a fordítónak bemásolnia. Más szóval: egy bázisosztály virtuális mintájának konkrét jelentése a bázisosztály alosztályaiban (származtatott osztályaiban, almintáiban) adható meg pontosan (illetve terjeszthető ki).

worker és salesman: az employee osztályminta almintái (subpattern), vagyis őket származtattuk az employee-ból (közvetlen leszármazottak). A computeSalary virtuális minta konkrét jelentését is itt adjuk meg; a ::< jelcsoport jelzi azt, hogy kiterjesztjük az ősosztályban megadott virtuális mintát, vagyis az ősben szereplő innert a most (a do rész után) megadott utasításokra kell (gondolatban) kicserélni. A ::< jelcsoporttal azt jelezzük, hogy a további származtatás esetén még mindig tovább akarjuk terjeszteni az adott mintát. Ha nem ez a szándékunk, akkor kell használni a :: jelpárt (a BETA terminológia final bindingnak nevezi ezt a jelpárt, kb. végső jelentés), ami azt jelzi, hogy az adott mintát már nem kívánjuk tovább építeni, vagyis az esetleges további származtatás esetén sem akarjuk a jelentését tovább bővíteni. Ebben az esetben természetesen az inner kulcsszót el kell hagyni a minta do részéből.

Még egy fontos megjegyzés az inner kulcsszóval kapcsolatban: ezzel a szerkezettel csak egy már meglévő rész továbbépítését végezhetjük el, vagyis az ősosztályokban megadott részfunkciókat nem lehet a virtuális mintákkal átdefiniálni (kicserélni)!

A worker és a salesman osztályon keresztül az öröklődésre is láthattunk példát.

A BETÁ-ban tehát az almintaképzés mechanizmusa a virtuális eljárásminták kiterjesztésével kombinálva jelenti az öröklődést, vagyis ily módon az alminták öröklik az ősmintáik (szupermintáik) tulajdonságait.

A fenti kódrészletekben tehát példát láthattunk osztály- és eljárásmintára, valamint almintára is. Az almintákban új attribútumokat vezethetünk be, kiterjeszthetjük a szupermintában (ősben) megadott virtuális minták definícióit, és megadhatunk új utasításokat is, amelyek a szuperminta utasításaival kombinálva hajtódnak végre; ezt támogatja az inner szerkezet.

6.példa

Példa egymásba ágyazott mintákra:

(Eddig volt egy külső egymásba ágyazás az osztályok szintjén, és egy belső az eljárások szintjén. Most részobjektumok lesznek.)

... Product: (# name: @Text; Order: (# date: @Date; color: @Text; Print:< (# do inner; name->puttext; color->puttext; #) #) #); p1,p2: @Product; o1: @p1.Order; o2: @p2.Order; ... o1.Print; o2.Print; ...

Ekkor az o1.Print ki fogja írni a p1.name-t is, hasonlóan a o2.Print kiírja a p2.name-t is.