A BETA programozási nyelv

Objektum-orientáltság



Osztályok

Egy minta tartalmazhat tagmintákat is, amik lehetnek akár alprogramok is. A mintákat ki lehet terjeszteni, ez felel meg az öröklődésnek. A tagmintáknál meg kell adni, hogy melyik tag legyen virtuális, és melyik nem, illetve azt is, ha egy ősmintabeli tagot akarunk kiterjeszteni. Többszörös öröklődés nincs. Az objektumok közötti értékadás nem megengedett, csak a referenciát lehet módosítani. A minta tagjainak láthatóságát nem lehet korlátozni, minden mindenhonnan látható.

Minták és öröklődés

Virtuális minták esetén nincs hagyományos értelemben vett öröklődés, viszont van valami nagyon hasonló: a kiterjesztés. (Ha a minta nem virtuális, az öröklődés a felüldefiniálással egyenértékű.) A továbbiakban ezt öröklődésnek nevezzük. A minták öröklődésének formája:

P::<S (# decl_1; decl_2; ...; decl_n; enter (in_1, in_2, ..., in_m) do imp_1; imp_2; ...; imp_k; exit (out_1, out_2, ..., out_l) #)

Ahol

Az fent deklarált P egy olyan minta lesz,

Ha p_obj egy P mintájú objektum, akkor a végrehajtását a kódban egyszerűen a p_obj kifejezéssel, illetve a (... megfelelő paraméterek...) -> p_obj utasítással érhetjük el.
A p_obj végrehajtása három részből áll:

  1. Az enter-listában szereplő adatattribútumok megkapják a nyíl baloldalán szereplő értékeket (sorrend szerint). Ha nincs nyíl, akkor ezek az attribútumok a megfelelő nullértékeket kapják.
  2. Végrehajtódik a do részben szereplő utasítás-sorozat (az S minta do részében szereplő inner utasítások helyén a P minta do részében megadott teljes utasítássorozat lefut).
  3. Készül egy lista az exit-listában szereplő objektumok aktuális értékeiből, ez lesz a visszatérési érték.
C:< (# A, B: @integer do 11->A; inner; 33->B; #) C1::< C (# D: @integer do 22->D; #)

Ekkor a lefutási sorrend: 11->A; 22->D; 33->B;

Mint már említettük, van egy Object nevű minta, ami minden mintának az őse, bár ezt nem írjuk ki. Ennek segítségével lehet olyan eljárás-mintákat írni, melyek valamilyen egyéb mintával vannak paraméterezve. Ennek technikája az, hogy a mintában felveszünk egy

R:< ^Object

változót, és ezt a változót majd örököltetés közben átdefiniáljuk:

R::< ^Valami

Példa:

register: (# type:< object; insert:< (# e: ^type enter e[] do #) #)

A type bármely mintával átdefiniálható a register minta leszármazottjaiban, mivel az objectből származik, ami a legáltalánosabb szuperminta.

workerRegister: register (# type::< worker; findOldestSeniority: (# old: @integer do scan (# do (if current.seniority > old then current.seniority->old if) #) exit old #) #);

A workerRegiter mintában, mely a register almintája, a type attribútumot workerre definiálja át.

Késői kötés

Lehetőség van virtuális minták definiálására is, ahol a virtuális minta deklarációja úgy néz ki, hogy:

A: (# Nev:< (# ... #) #); B: A (# Nev::< (# ... #) #);

illetve

C: A (# Nev:: (# ... #) #);

Ahol az A.Nev egy virtuális minta (általában függvény), a B.Nev az A.Nev virtuális kiterjesztése és tovább kiterjeszthető, a C.Nev pedig szintén az A.Nev virtuális kiterjesztése, de tovább már nem terjeszthető ki, azaz úgy döntünk, hogy ez a végső változat (final binding). Ez annyiban újdonság, hogy az így deklarált mintákra késői összekapcsolás teljesül, azaz csak futásidőben dől el, hogy milyen kód fog lefutni egy függvényhívásra, tehát ez megfelel más nyelvek virtuális függvényeinek, de annyiban különbözik, hogy nem definiálhatók át, csak kiterjeszthetők.