A Modula3 programozási nyelv

Típusok, típuskonstrukciók

Típusszerkezet

A Modula-3 nyelv erősen típusos, mint az Algol családjába tartozó nyelvek általában. Az erős típusosság felvet néhány problémát, melyeket a különböző nyelveken más és más módon oldottak meg. Például:

A Modula-3-ban a típusrendszert megpróbálták annyira egységesíteni, amennyire csak lehet. Néhány alapszabály, melyet követtek:
Ezenkívül fontos megjegyezni, hogy a Modula-3-ban (ellentétben például a Modula-2-vel) strukturális típusekvivalenciát alkalmaznak. Azaz, a következő példában x és y ekvivalens, míg a Modula-2-ben nem voltak azok.

 x: ARRAY [0..9] OF INTEGER;
y: ARRAY [0..9] OF INTEGER;

A típusdeklaráció fordítási időben értékelődik ki, ezért a típusok statikusak. Ahol típust vár a nyelv, oda típuskifejezést is írhatunk.

Egy típus üres, ha értékhalmaza üres, pl. [1..0] üres típusokat használhatunk más típusok felépítésekor, pl. SET OF [1..0] nem üres, mert tartalmazza az üres halmazt. Amennyiben egy változót üres típusának deklarálunk, fordítási hibát kapunk.

A típuskompatibilitás az egyszerű altípus reláción alapul. Eszerint egy X típus altípusa egy U típusnak (X <: U) ha X értékhalmaza részhalmaza U értékhalmazának.

A típusdeklaráció a TYPE kulcsszóval kezdődik, ezt követi az azonosító és a típus megadása:

TYPE  "="  ";" 

Elemi típusok

Diszkrét típusok

INTEGER
32 bites előjeles egész szám. Előredefiniált függvények:



Aritmetikai számítások: +, -, *, div (a legközelebbi egész számot adja meg, amely kisebb a hányadosnál), mod x MOD y = x - y*(x DIV y). Ha y >0, akkor x mod y értéke 0..y-1 között van. Ha y<0, akkor y+1..0 között.
MOD és DIV előjelének különbsége:
x y x DIV y x MOD y
9 4 2 1
-9 -4 2 -1
9 -4 -3 -3
-9 4 -3 3
Reláció operátorok integereken: =, # (nem egyenlő), >, <, >=, <= Altípusok: Subrange=[lowerBound..upperBound]

BOOLEAN
{TRUE, FALSE}. Műveletei: AND, OR, NOT

CHAR
Legalább 256 elemből álló típus (leggyakrabban ASCII karakterek).
\n (soremelés), \t (tabulátor), \' (aposztróf), \\ (perjel), \" (idézőjel).
Karakterekre érvényes relációk:

'A'<'B'<'C'<...<'X'<'Y'<'Z'
'a'<'b'<'c'<...<'x'<'y'<'z'
'0'<'1'<'2'<...<'7'<'8'<'9'

Műveletek: ord (sorszámát adja meg), val (az ordnak az inverze), inc, dec, first, last (többi típusra is használhatók).

TEXT

CHAR típusú elemek tetszőleges hosszú sorozata. Az ilyen típusú változók referenciák, ezért ezeknek az egyenlőségét a Text interfészben deklarált Equal függvénnyel lehet csak vizsgálni.
Egyéb műveletek: & - konkatenáció, Length - hossz, GetChar - adott indexű karakter elérése. Különbség konstans karakter és konstans text között:

CONST
CharConst = 'A';
TextConst = "A";

Ezek különböző típusúak! Az egyik egy karakter, a másik egy egy hosszúságú text.

Valós típusok (REAL, LONGREAL, EXTENDED)

E: real, D: longreal, X: extended
Különböző pontosságú lebegôpontos típusok. Műveleteik: +, -, *, /
Példák:

1.1 REAL típusú;
1.1D0 LONGREAL, értéke: 1.1
1.1X0 EXTENDED, értéke: 1.1
1.5e2 REAL, értéke:150
-1.5x+2 EXTENDED, értéke: -150
1.5E-3 REAL, értéke: 0.0015

Műveletek REAL és INTEGER között:
FLOAT(i): INTEGER->REAL.
FLOAT(r, LONGREAL): REAL->LONGREAL.
ROUND(r): REAL->INTEGER: kerekítés: a legközelebbi egész számot adja meg.
TRUNC(r): REAL->INTEGER: levágja a tizedespont utáni jegyeket.
FLOOR(r): REAL->INTEGER: lefele kerekít.
CEILING(r): REAL->INTEGER: felfelé kerekít.

Az alaptípusokra relációs műveleteket is lehet használni: = az egyenlő, # a nem egyenlő logikai operátor; a <, >, <=, >= a megszokott relációs operátorok.

Mutató és referencia típusok

Kétféle referencia-típus létezik. Az alapértelmezett az un. TRACED POINTER, melynek felszabadításáról az automatikus szemétgyűjtő gondoskodik. A másik, az UNTRACED (REF) kulcsszóval ellátott pointer fajta esetében erre nekünk kell figyelni. Létezik még három predefinit altípus, a REFANY, ADDRESS, NULL, melyekre a következő altípus-relációk teljesülnek:

NULL<:REF T<:REFANY és NULL<:UNTRACED REF T<:ADDRESS.
A NULL típus egyetlen lehetséges értéke a NIL, azaz a null pointer.
TYPE IntPtrType = REF INTEGER; ArrPtrType = REF ARRAY [1..5] OF CHAR;
Példa:
TYPE StudentRef = REF Student; Student = RECORD CatalogNo: INTEGER; Firstname, lastname: TEXT; END; VAR ref1, ref2: StudentRef; BEGIN ref1:=NEW(StudentRef); (*create data record with address in ref1*) ref1.catalogNo:=1; (*set fields of new data record*) ref1.firstname:="Peter"; ref1.lastname:="Tall"; ref2:=NEW(StudentRef, catalogNo:=2, firstname:="Julie", lastname:="Short"); (*data record created and initialized*) ref2:=ref1; (*ref2 now points to first record; thus second cannot be referenced*) ref1:=NIL; (*first record can still be referenced with ref2*) ref2:=NIL; (*now second record is also inaccessible*)

Típuskonstrukciók

Tömb típusok

Két alapvető fajtáját különböztetik meg:

ARRAY { "," ... } OF ";"
Az indextype-nak rendezett típusának kell lennie. Ez általában INTEGER típus szokott lenni, de lehet bármilyen felsorolási típus is. A slottype minden Modula-3-beli típus lehet. Példák:
Beépített műveletek a FIRST, LAST, NUMBER, amelyek a tömb első ill. utolsó indexét, valamint a számosságát adják meg, pl:
FIRST(OneDimArray) = 1; NUMBER(OneDimArray2) = 26.
Pakolt típusnak befolyásolhatjuk a belső reprezentációját. Például megadhatjuk, hogy egy BOOLEAN bázistípusú tömb egy-egy biten tárolja az elemeit. Helytelen méret megadás fordítási hibát eredményez. A BITSIZE művelettel lekérdezhető egy típus vagy változó mérete bitekben (a BYTESIZE-zal bájtokban). Pl.:
TYPE MonoBitMap=ARRAY Index1,Index2 OF BITS 1 FOR BOOLEAN;

Direkt szorzat típus

Rekord

> RECORD <fieldDecl> { ";" <fieldDecl> ... } END ";"
ahol
<fieldDecl> = <id> [ ":" <type> ] [ ":=" <constant expr> ]

Minden mezőnek van neve, típusa, és esetleg kezdőértéke. Pl.

TYPE Rec1 = RECORD x, y: INTEGER; name: TEXT
END; Rec2 = RECORD x, y := 0; (* Type is INTEGER *) name := "" (* Type is TEXT *) END; TYPE EmpData = RECORD name, firstname: TEXT; salary: REAL; END; (*Valtozo:*) VAR employee: EmpData; (*Szelektor:*) q.x := 10;

A szokásostól (pl. Modula-2, Pascal) eltérően, rekord konstanst nem csak pozicionálisan, hanem név szerint kötve is megadhatunk, pontosan úgy, ahogy az eljáráshívásnál láthatjuk.

Pozicionális Point{20,30}, név alapján: Point{y:=30, x:=20}, kevert: először a pozicionálisak, ezt az értékadási módot el szoktuk kerülni, mert nehezen olvasható.

Sokszor előfordul olyan eset, amikor egy rekord különböző mezőire hivatkozunk egymás után többször is. Ha ekkor még a rekord többszörösen összetett is, akkor nehézkes mindig ugyanazt leírni. A Modula-3-ban erre szolgál a WITH parancs. A parancs után felsoroljuk a rövidítéseket, és ezek értékét. Az ezt követő BEGIN/END között lesznek ezek érvényesek.

WITH <id> "=" <expr> { "," <id> "=" <expr>... } DO <stmts> END

Unió típus

Halmaz típus

Nem indexelhetők az elemek, mert nincs sorrendjük.

TYPE Keys = {left, right, middle}; Mouse = SET OF Keys; VAR mouse: Mouse
Relációk, műveletek: unió (+), különbség (-), direktszorzat (*), szimmetrikus differencia (/). Egyenlőség (=), nem egyenlő (#), részhalmaz (<=, <, >=, >), tartalmaz (IN).

Típuskonverziók

Változók, konstansok

A változódeklarációkat VAR, a konstansdeklarációkat CONST kulcsszóval kell kezdeni. Mindkettőnél meg kell adni egy azonosítót, majd kettőspont után egy típust és/vagy egy kezdőértéket. Ha nem adunk meg típust, akkor a kezdőérték típusát használja a fordító. A konstansoknál kötelező a kezdőérték megadása, és ez az érték később nem változhat meg.
Példák:

VAR a,b,c: type; a,b,c: type := expression; a,b,c:=expression; CONST MaxValue: INTEGER = 5 * (25 - 3); (* INTEGER *) MinValue = 2; (* INTEGER *) Caps = SET OF CHAR {'A'..'Z'}; (* SET OF CHAR *) A = 10; B = 2*A; TYPE Workdays = [Days.Monday..Days.Friday] CONST Weekdays = NUMBER(Workdays);
Konstans deklarációnál nem kötelező megadni a típust. De meg lehet:
CONST A : CARDINAL = 0; VAR Value: INTEGER; (* INTEGER kezdőérték nélkül *) Char = 'F';

Kifejezések, operátorok