A Theta programozási nyelv

Típusok és paraméterezett típusok

A típus (type) objektumok (object) halmazából áll, az objektumhoz tartozó metódusokkal együtt. A metódus hozzáférhet és megváltoztathatja az objektum állapotát. Ha egy objektumnak nincsen olyan metódusa, ami megváltoztathatja az objektum absztrakt állapotát (abstract state), azt mondjuk, hogy az objektum immutable (változtathatatlan), egyébként mutable (változtatható). Egy típus immutable/mutable ha az objektumai immutable-k/mutable-k.

A paraméterezett típus egymással kapcsolatban lévő típusok családját definiálja. Például az "array" (tömb) paraméterezhető típus definiálja az "array[int]", "array[char]", "array[array[int]]" stb. típusokat. A család minden típusához hozzájuthatunk a paraméterezett típus példányosítása során, új típus ily módon való létrehozását példányosításnak nevezzük.

A Theta-ban számos beépített és paraméterezett típus található. Ráadásul a felhasználók is definiálhatnak új absztrakt típusokat és paraméterezett típusokat.

A Theta-ban erős statikus típusellenőrzés van. A típusok típus hierarchiába vannak szervezve: egy típus különböző típusok altípusa lehet. A beépített típusok hierarchiája elég lapos, kivéve a rutin típusok bő hierarchiáját. A felhasználók definiálják a felhasználó által definiált típusok hierarchiáját. A típus hierarchia meghatározza az értékadások és a rutinhívások helyességét.

A típusleíró egy típust jelöl. Például, egy típusleíró lehet egy felsorolási típus ("int", "color"), vagy egy paraméterezett típus egy előfordulása ("array[int]", "maybe[employee]").

Beépített típusok

A beépített típusok a következők: "null", "any", "bool", "char", "int", "real", "string" és minden rutin típus. A beépített paraméterezhető típusok pedig: "array", "sequence", "vector", "record", "struct", "oneof", and "maybe".

Az "any" típusnak nincsenek metódusai, ez áll a típus-hierarchia csúcsán. Minden típus (a beépítettek és a felhasználó által definiáltak is) ennek altípusa.

A "null" típusnak egy literálja van a "nil". A "bool" típus a szokásos logikai típus, két literállal "true" és "false". Az "int" típus az egész számok, míg a "real" típus a fixpontos valós számok reprezentációja. A "char" típus a karakterek tárolására használható (általában ASCII), míg a "string" típus segítségével reprezentálhatunk karaktersorozatokat (ez is általában ASCII sztringek).

A paraméterezhető típusok "array", "vector" és "sequence", homogén gyűjtemények, melyek egymást követő egész számokkal indexeltek. Az "array" és a "vector" mutable típusok, a "vector" fix méretű, míg az "array" típusnak dinamikusan nőhet vagy csökkenhet a mérete. A "sequence" egy immutable típus. A "record" és a "struct" speciális heterogén típusok mezőnevekkel, és hozzájuk tartozó szelektorokkal. A "record" mutable típus, míg a "struct" immutable. A "oneof" egy speciális megnevezett, immutable unió típus. A "maybe" a "oneof" egy másik típusa, mely a paraméter-típus objektumait, illetve a "nil" értéket tartalmazhatja.

A rutin típusok szintén a Theta beépített típusai. A rutinok (azaz ezen típusok objektumai) a rutin specifikációk és rutin implementációk. A rutinok is objektumok, így tárolhatók adatstruktúrákban, átadhatók paraméterként, vagy visszatérési értékként.

Típus megnevezések (jelölések)

A típusoknak 4 különböző fajtája van a Theta-ban, és mindegyiknek sajátos jelölési formája van. Ezeket a formákat magyarázzuk meg a következő részekben. Típus jelöléseket szintén definiálhatunk egyenlőségekkel is.

Szimpla típus

Sima típusokat nem paraméterezett típus specifikációval definiálhatunk. Ide tartozik az összes felhasználó által definiált nem paraméteres típus, és néhány beépített típus. A egyszerű típusokat a nevükkel nevezzük meg:

<simple_type_desig> -> <idn> | 'null' | 'bool' | 'char' | 'int' | 'real' | 'string' | 'any'

Paraméterezett típus

A paraméterezett típus egy vagy több típus-paraméterrel rendelkezik. A típus-jelölés az ilyen típusnál azt jelenti, hogy a
mindegyik típus-paraméterbe aktuális típusokat helyettesítünk be:

        <parm_type_desig> -> <parm_type> "[" <type_list> "]"
 
ahol
<parm_type> -> <idn> | array | sequence | vector | maybe
<type_list> -> <type_designator> ["," <type_designator>]*

A paraméterezett típus specifikációja ott használható, ahol a megkövetelt kikötések azok, hogy az aktuális paramétereknek meghatározott (bizonyos) metódusokkal rendelkezniük kell. A paraméterezett típus egy szemléltetése (egy bemutatása) megengedett, ha helyes számú aktuális paraméterrel rendelkezik, és az aktuális paraméterek teljesítik az ottani kikötések megszorításait. Például. nézzünk meg egy felhasználó által definiált paraméterezett típust a "set[T]"-t. Mivelhogy a halmaz nem tartalmazhat kétszeresen egy elemet, ezért a "set" specifikációját akkor engedélyezi, ha az argumentum típus rendelkezik egy egyenlőség
(egyenlőséget vizsgáló) metódussal (amivel az ilyen kettősség felismerhető):

set = type [T] where T has equal: proc (T) returns (bool)

Itt van néhány példával való szemléltetése a "set"-nek:

set[int] % az int egyenlőség metódusát helyettesíti a T egyenlőség metódusába
set[array[int]] % az array[int] egyenlőség metódusát helyettesíti a T egyenlőség metódusába
set[int,bool] % nem megengedett - fordítási időben jelentkező hiba
set[employee] % akkor megengedett ha employee rendelkezik egy egyenlőség metódussal

A harmadik példa nem megengedett, mert nem megfelelő számú paramétert helyettesítettünk be. Az utolsó példa csak akkor megengedett, ha az "employee" típus rendelkezik egy "equal" (egyenlőséget vizsgáló) metódussal. Ha nem rendelkezik, akkor fordítás hibával áll le.

Egy paraméterezett típus néhány metódusa esetleg elhelyezhet kiegészítő megszorításokat egy paraméterre, ahol ezeket saját kikötésiként birtokolja. Az ilyen metódus tetszés szerinti (nem kötelező): ha egy példa (szemléltetés) teljesíti ezt a megkötést, akkor a (következő) eredő típusnak rendelkeznie kell a metódussal egyébként nem. Ha egy ilyen paraméterezett típust nevezünk meg, akkor a metódusainak teljesíteniük kell az opcionális metódusok megszorításait ha ez lehetséges. A következmény (a származtatott típus) egy típus lesz az összes nem opcionális metódussal, plusz néhánnyal az opcionális metódusokkal, amelyek megszorításai teljesülnek. például. az "array"-nak van egy opcionális "copy" metódusa, ami akkor létezik (akkor tételezzük fel), ha az aktuális paraméter rendelkezik "copy" metódussal. Itt van pár példa.

array[int]                              % van copy metódusa
array[employee] % lehet hogy nincs copy metódusa

Ha az "employee" nem rendelkezik "copy" metódussal, akkor a származtatottaknak az "array" típusban nincs "copy" metódusuk.

Rutin típusok

A rutinoknak két fajtája van, eljárások és iterátorok. A rutin típus megvalósítása a következő speciális formát követi.

<routine_type_desig> -> proc <nonparam_proc_sig> | iter <nonparam_iter_sig>
<nonparam_proc_sig> -> "(" [<type_list>] ")" [<returns>] [<signals>]
<nonparam_iter_sig> -> "(" [<type_list>] ")" <yields> [<signals>]
<type_list> -> <type_designator> ["," <type_designator>]*

Ezek a típus-megvalósítások jelzik a rutinok fajtait, az argumentumok számat és típusát, a visszatérési érteket, és a megszakításokat. Például.

proc(int, int) returns (bool) signals (negative)
iter(stree[int]) yields (int)

Megjelölt típusok

A megjelölt típusok közé tartoznak a "record", "struct" és a "oneof" típusok. Ezek speciális paraméterezhető típusok, amelyek tartalmaznak névvel jelölt mezőket, és a következő speciális formát követik:

<tagged_type_desig> -> <tagged_type> "[" <field> ["," <field>]* "]"
<tagged_type> -> 'record' | 'struct' | 'oneof'
<field> -> <idn_list> ":" <type_designator>

Ezek a típus leírások gondoskodnak minden egyes mező nevet, és adnak nekik típust. Például.

record[x, y: int, s: string]

definiál egy rekord típust. ennek a típusnak a rekordjainak három mezőjük van: két "int" mező, amit "x"-nek, és "y"-nak hívnak, és egy "string" típusú mező, amit "s"-nek nevezünk.

Típus-azonosság

A típus-ellenőrzés a Theta-ban fordítási időben történik, és a típus leírások elemzésen alapul, azaz meghatározza vajon azonos típust jelölnek-e. Két típus-meghatározása azonos, ha ugyanazt a típust jelölik, egybekent különbözőek.

A típus-azonosság a következőképp van definiálva:

  1. minden egyszerű típus csak önmagával azonos.
  2. két típus egyenlő, ha ugyanolyan paraméterezett típust jelölnek, a paramétereik páronként megegyeznek.
  3. két rutin típus megegyezik, ha mindkettő proc, vagy mindkettő iter, megegyezik az argumentumok száma és az összeillő argumentumok típusa megegyezik. a visszatérési értékek száma megegyezik, és az összeillő visszatérések típusa megegyezik, ugyanazokkal a megszakításokkal rendelkeznek, és az összeillő megszakítások ugyanannyi és ugyanolyan típusú visszatérésekkel rendelkeznek.
  4. két megjelölt típus azonos, ha ugyanazzal a tagged_type típussal rendelkeznek, ugyanolyan mezőnevekkel rendelkeznek, ugyanabban a sorrendben, és az összeillő mezőnevek típusa megegyezik. A következő két típus nem egyenlő:
      record[a: int, b: int]
      record[b: int, a: int]

 

Típus hierarchia

A típusok a Theta-ban típus-hierarchiában csoportosulnak. minden egyes típus rendelkezik néhány szupertípussal. A hierarchia csúcsán az "any" típus áll, aminek nincsenek metódusai, és szupertípusa minden típusnak.

A típus hierarchia a típus-azonosság fogalmán alapszik. Egy típus mindig altípus, és szupertípusa is önmagának. Az altípus, és szupertípus reláció is tranzitív:
ha T altípusa az S-nek, és S altípusa R-nek, akkor T altípusa R-nek.

Az "any" az egyetlen szupertípusa a beépített típusoknak, kivéve a gazdag hierarchiával rendelkező rutin típusok. Nevezetesen, semmilyen altípus relációkkal a record és struct típusok nem lettek ellátva.

record[a: int, b: int, c: int]

nem altípusa a

record[a: int, b: int]

A felhasználó által definiált típusok, és a felhasználó által definiált paraméterezett típusok világosan mutatják a közvetlen szupertípusokat. Minden szupertípusnak felhasználó által definiáltnak kell lennie, kivéve ha miden felhasználó által definiált típus egy altípusa lesz automatikusan az "any"-nek.

Minden típus generál egy felhasználó által definiált típust, amely éppúgy altípusa az "any"-nek. A Theta fordító garantálja, hogy az altípusok rendelkeznek a szupertípusaik összes metódusával kompatibilis szignatúrával.

Rutin típus hierarchia

R1 rutin típus altípusa az R2 rutin típusnak, ha az összes most következő feltételek teljesulnek:

  1. a mindkét rutin típusnak proc tip, vagy iter típusnak kell lennie.
  2. az argumentumok kontravarianciája: azonos számú argumentummal kell rendelkezniük, és ugyanabban az argumentum pozícióban R1 argumentumának típusa szupertípusa kell hogy legyen R2 argumentumának típusának.
  3. a visszatérési értékek (eredmények) kovariaciája: ha mindkét rutin procedure típusú, akkor a visszatérési értékek száma meg kell hogy egyezzen, és az R1 visszatérési értekének típusa altípusa kell legyen a vele összhangban levő R2 visszatérési értek típusának.
  4. hozamok kovarianciája: ha mindkét rutin iterátor típusú, akkor a hozamok száma meg kell hogy egyezzen, és az R1 hozam típusa altípusa kell legyen a vele összhangban levő R2 hozam-típussal.
  5. R1-ben nem lehet olyan megszakítás, ami nem megszakítás az R2-ben is.
  6. kivételek eredményeinek kovaranciája: az egymásnak megfeleltetett kivételek (összhangban levő kivetélek), azonos számú eredménnyel (visszatérési értekkel) kell hogy rendelkezzenek, és az R1 eredmény típusa altípusa kell legyen az R2 eredmény típusának.

Ezek a szabályok biztosítják, hogy egy R1 típusú rutin hívása mindig megengedett akárhol, ahol az R2 típusú rutin hívása előre látott (engedélyezett). nevezetesen, a rutin nem fog okozni váratlan kivételeket.