Az Alphard programozási nyelv

Típusok, típuskonstrukciók


Az Alphard nyelvet a következõ célok együttes elérése érdekében hozták létre: Így az Alphardban a központi szerep a kód összetételében, a strukturált fejlesztésben rejlik, ezáltal pl. az egyszerû adattípusok száma nagyon alacsony. A fejlesztõk ezt azzal magyarázzák, hogy így egyszerûbb a nyelv, és a meglévõ típusokból amúgy is felépíthetõek a szokásos adattípusok.
A fejlesztõk a biztonságosságot és hatékonyságot tartották szem elõtt, ami néha a rövidség és kényelem rovására megy.

Nyelvi elemek

Az Alphard nyelvi konstrukciói az Algol - Pascal vezérvonalra támaszkodnak.
Például:

begin var x,y,z :int; ... if x>=y then z:=z+1 fi; ... end;
Vannak azonban eltérések ezektõl a nyelvektõl:

Típus definíciók: Minden új típus definiálása a form konstrukció segítségével történik. Egy forma magában foglalja a típusunk specifikációját és implementációját. Készítésekor támaszkodhatunk a már megkonstruált formákra, és egyéb létezõ típusokra. A forma paraméterezhetõ, akár típussal is, ezáltal sablonokat (generic) hozhatunk létre.

Egyszerû (beépített) típusok: A többi nyelvhez képest lényeges különbség, hogy itt az integer, real nem egyszerû típusok, ahogyan az array, record sem az. Mindössze két egyszerû típus található a nyelvben: rawstorage és boolean. A többi típus is elérhetõ (standard könyvtárakban), mint konstruált formák.

Típusmegfeleltetés: Ugyan egy erõsen típusos nyelv volt a cél, azonban ezen kénytelenek voltak engedni a típus paraméterezhetõsége miatt. A fõ gondot a formális és aktuális paraméterek megfelelése okozza, ezt úgy küszöbölték ki, hogy a formális paraméterek definiálásakor specifikálni kell egy tulajdonsággyûjteményt, ami a lehetséges aktuális paraméterek osztályát adja meg.

Hatáskör, láthatóság: Az Alphard blokkszerkezete az Algol 60-éhoz hasonló (a deklarációk a blokk elején találhatók, egy hivatkozás típusát a blokkstruktúrában felfelé haladva érhetjük el), de itt az eljárások és formák törzse nem örökli a bennfoglaló blokkok változóinak nevét.

Operátorok definiálása: Lehetõsége van a programozónak, hogy saját típusai számára definiálja a szokásos infix operátorokat ("+", "*", stb). Az alapvetõ tulajdonságaikat azonban nem definiálhatja felül (asszociativitás, precedencia).

Szelektorok: Az adatstruktúrák reprezentációját szelektorok segítségével adhatjuk meg. Egy szelektor (selector) az adatok szolgáltatására ad algoritmust. Úgy kell felépülnie, mint egy olyan függvénynek, ami a struktúra egy elemére mutató referenciát ad vissza.

A változódeklarációk kiértékelése:

var x: vector(int,1,10)
Kiértékelése a típus leírás (vector(int,1,10)) kiértékelésével kezdõdik, majd a típusnak megfelelõ objektum létrehozásával (hely allokálásával és az inicializáló mûveletek végrehajtásával) folytatódik, végül az objektum és a deklarációban megadott név között kötés jön létre.

A rutinok hívásának kiértékelése:

f(x, y)
az aktuális paraméterek (x és y) kiértékelésével kezdõdik, majd a paraméterek névleges típusának és a formális típus deklarációnak az egyeztetése következik, ami ha sikeres, létrejön a kötés, és a rutin törzse értékelõdik ki.

A most következõ szakaszban a fent dõlt betûvel jelzett kifejezések leírása található.

Objektumok, címek és értékek

Intuitívan az objektum egy generált tárolási hely vagy változó, amit absztrakt adattípusok adatainak tárolására használunk.

Egy objektumnak típusa, értéke (állapota) és egyedi címe van. Az objektumokat dinamikusan lehet létrehozni és felszabadítani. A címe és típusa állandó az "élete" során, míg az értéke változik. Az objektum primitív, ha értékeit egy tetszõleges (egyszerû) halmazból veszi fel, egyébként pedig egy vagy több, elõzõleg definiált objektum összetételébõl áll (ezek az õ konkrét komponensei). Egy ilyen objektum értéke a konkrét komponensei értékeibõl áll össze.

Két objektum átfedi egymást, ha értékeik nem függetlenek. (Pl. ha az egyik tartalmazza a másikat, mint vektor az elemét.) Azon objektumok, melyek nem fedik át egymást függetlenek. Bármilyen logikai összefüggés a két objektum között fix kell legyen. Egy újonnan létrehozott, eddigiektõl független objektumot új objektumnak nevezünk.

Egy objektum létrehozása a számára szükséges hely allokálásából és az értékeinek inicializálásából áll. Elsõ lépés a típus kiértékelés, ezután jön létre az objektum (primitívek esetén ez egy lépéses, összetett objektumok esetén a komponensek rekurzív létrehozását jelenti). Ez után hajtódik végre az inicializáló (konstruktor) eljárás.

Egy objektum felszabadítása a destruktor eljárás (az osztálytípusában definiált) hívásával kezdõdik, majd a komponensek rekurzív felszabadítása után a saját helye is felszabadul.

Típusok és leírásuk

Az Alphardban is igaz, hogy érték nem létezik "csak úgy", minden érték egy objektumban tárolódik, ezáltal minden értéknek van típusa.

A nyelvben két explicit típus létrehozás található: a form deklaráció (ami egy osztályt definiál), és a típus leírás.

Egy forma lényeges tulajdonságai: van neve, paraméterezhetõ és lehetõvé teszi eljárások hívását.

A típus leírást három helyen alkalmazható: változók deklarálásakor (megadjuk az objektum típusát), formális paraméterek specifikálásakor (ekkor a lehetséges aktuális paraméterek típusát adjuk meg), és függvények definiálásakor (amikor is a visszatérési érték típusát állítjuk be).
E fentiek azt követelik meg, hogy minden változónak legyen egy névleges típusa, ami azt mondja meg, hogy milyen környezetben alkalmazható.

Típus

Egy típus a típus leírás kiértékelésének eredményét tartalmazza, és az alábbi három tulajdonsággal bír:

1. Bázis típus: ami az õt leíró form neve. A "vector(real, 1, 12)" példában a "vector" a bázis típus. ( T típus bázis típusa: Base(T) ).

2. Aktuális típusleírók (Qual(T)): a típus leírás aktuális paraméterei, ami a form formális paramétereitõl függõ. Ez egy objektum címe, egy objektum, a rutin neve egy típus, illetve egy jelzõ (unk). A "vector(real, 1, 12)" példában az aktuális típusleírók a "real", az "1" és a "10".

3. A módosító halmaz (Update(T)): azokból a rutinokból áll, melyek a típusnak megfelelõ objektumon látható változásokat idéznek elõ. (Megváltoztatják az állapotát.)

Névleges típus

A névleges típus - mint a típus - szintén egy bázistípusból, (egy valószínûleg üres) aktuális típusleíró részbõl és egymódosító halmazból áll.
Egy típus mindig egy objektummal van kapcsolatban, míg a névleges típus egy azonosítóval. A névleges típus kevésbé specifikus, mint a típus. Egy objektum típusa azonban mindig meg kell egyezzen az azonosító névleges típusának.

Kötés

A kiértékelés során egyes azonosítókhoz entitások kapcsolódnak - kötõdnek. Ezek az entitások objektumok, rutinok vagy típusok lehetnek. A kötés létrejöhet változó deklarálásakor vagy paraméterátadáskor.
Amikor egy kötés létrejön, létrejön egy hozzárendelt típusleírás is. Változó deklarálásakor ez a létrejött objektum típusát jelöli, paraméterátadáskor a formális paraméterek által definiált, az aktuális paraméterek lehetséges értékeit meghatározó típust.
Mindkét esetben két kulcsszó vezetheti be a kötést: a var és a const. A const a módosító halmazt üresre állítja, míg a var esetén az aktuális típusleírók határozzák meg.
Ha k-val egy objektumhoz kötött azonosítót jelölünk, akkor Obj(k)-val jelöljük az objektumot, Type(k)-val a névleges típust.

Típus megfelelés

A paraméter kötés megköveteli, hogy az aktuális paraméterek megfeleljenek a formális paramétereknek. A típus megfelelés három részre bontható: magába foglalás, szintaktikai megfelelés és implicit kötés:
Az aktuális paraméterek egy A1, ... An listája megfelel a formális paraméterek egy F1:T1, F2:T2, ... Fn:Tn listájának (ahol Ai-k objektumok, típusok vagy rutin nevek), ha minden i-re:

Def: Egy Tf (névleges) típus magába foglalja a Ta (névleges) típust (Tf >>Ta), ha

Def: Két típus megegyezik, ha mindkettõ magába foglalja a másikat.

Def: T generic paraméterre: form T specs <definitions of f1, ... , fn> és Q aktuális típusra Q (a1, a2, ...) mely bázistípusának deklarációja form Q(p1, ...) specs ... azt mondjuk, hogy Q(a1, ...) szintaktikailag megegyezik T-vel, ha Q(a1, ...)-nek T -be történõ szöveg szerinti helyettesítése után az f1, ..fn deklarációk megegyeznek a Q specifikációjában megadottakkal (formális paraméterek esetleges átnevezése után).

Def: Tf formális, Ta aktuális típus. Ha Tf >>Ta kiértékelése során Base(Tf) vagy Qual(Tf) "?"-el jelölt, akkor implicit kötésben áll Base(Ta)-val vagy Qual(Ta)-val.

Pl.: az alábbi eljárás deklarációban:
proc P(x:vector(int,?lb,?ub)) is ...
lb és ub implicit formális paraméterek. Ekkor
... var y:vector(int,1,10) ... P(y) ...
esetén 1 és 10 implicit kötésbe kerül lb-vel és ub.vel.

Összefoglalva:



Formális paraméterAktuális paraméterMegfelelési szabály
x:form típus szintaktikai megfelelés
x: rutin név megfelelés 1. szabálya
x:?T objektum Type(object) szintaktikailag kielégíti T-t
x: objektum magába foglalás
unk bármi mindig megfelel
?T   megfelelés az implicit kötés után
rutin név rutin név azonos rutin