Oxygene

Típusok, típuskonstrukciók



Típus kikövetkeztetés

Változó típus kikövetkeztetéssel lehet lokális változókat deklarálni úgy hogy nem adjuk meg a típust, de ez csak akkor használható ha a változó típusa meghatározható a kontextusból. Például:

var x := new SomeTypeName(...);

Ez megegyezik ezzel:

var x : SomeTypeName := new SomeTypeName(...);

A típus kikövetkeztetést lehet alkalmazni alap típusokra nem csak osztályokra. Például:

var x := 3; var s := 'Hello';

Ilyenkor a lehető legszűkebb típus lesz a változó típusa, például: integer nem longint. Csak a lokális és az inline változóknál lehet használni a típus kikövetkeztetést.

Egész típusok

Név Méret Előjel Tartomány
ShortInt 1 bájt előjeles -128...127
SmallInt 2 bájt előjeles -32768...32767
Integer 4 bájt előjeles -2147483648...2147483647
LongInt 4 bájt előjeles -2147483648...2147483647
Int64 8 bájt előjeles -9223372036854775808 .. 9223372036854775807
Byte 1 bájt előjel nélküli 0...255
Word 2 bájt előjel nélküli 0...65535
LongWord, Cardinal 4 bájt előjel nélküli 0..4294967295

Valós típusok

Név Méret Tartomány
Single 4 bájt -1.5E-45...3.4E38
Real, Double, Extend 8 bájt -5.0E-324...1.7E308

Karakter típusok

Név Méret Tartomány
WideChar, Char 2 bájt Unicode

Karakterlánc típusok

Megegyezik a .NET System.Strings osztályával

Logikai típusok

Név Méret Tartomány
Boolean 1 bájt 0, 1, False, True

Mutató, referencia típusok

Mint a többi .NET alapú nyelvek többsége Oxygene is támogatja az úgy nevezett nembiztonságos kódot (unsafe code), amely első sorban mutatók használatát jelenti, azaz a típusellenőrzés gyengítését. Annak ellenére, hogy a szigorú típusellenőrzés növeli a kód biztonságát, némely esetben sokkal nagyobb teljesítmény érhető el mutatók használatával.
Pascal nyelv biztosít lehetőséget mutatók használatára, ezek Oxygen-ben is használhatóak, de ahhoz hogy ezeket használjuk ezt explicit módon meg kell engedni a projekt beállításaiban (Ezen kívül nembiztonságos kódot használó elem deklarációban is explicit módon kell jelölni ezt a szándékot).
Szintaxis:

Nembiztonságos kód következő elemeknél használható: metódusoknál, propertiknél, mezőknél, illetve lokális változóknál.
Például ha egy metódus törzsében szeretnénk használni mutató típusú lokális változókat, akkor a metódust unsafe-nek kell jelölni.
Bizonyos biztonság visszanyerése érdekében egy mutató „leszögezhető” (pinned). Ilyen „leszögezett” mutató által mutatott objektum nem mozdítható memóriában a mutató hatókörében.

method MainForm.Test2; var x: Integer; pinned; begin x := @MyIntegerArray[0]; x[0] := 15; x[10] := 12; … end;

Nullable típusok

Minden változónak vagy egy alapértelmezett értéke, amire inicializálódik, ha nem adtunk neki értéket. Azonban a nullable kulcsszó használatával elérhetjük, hogy az értéket ne az alapértékre inicializálja hanem nil-re. Ez a kulcsszó csupán kellemesebb reprezentációja .NET egyik generikus osztályának, Nullable<T>-nek. Azaz nullable Integer i; ekvivalens Nullable<Integer> i;-vel, de feltételezhetően könnyebben használható.

SomeClass = class b1: Boolean; // initialized to false b2: nullable Boolean; // initialized to nil i1: Integer; // initialized to 0 i2: nullable Integer; // initialized to nil

Ennek a típusnak az előnye, hogy könnyen ellenőrizni tudjuk, hogy egy változó kapott-e már értéket. Pl.:

var priority: nullable Integer; begin if assigned(priority) then ; // checks if priority isn't null if priority = nil then; // checks if priority is null if priority <> nil then; // checks if priority isn't null

Nullable osztályok kényelmesebb használata érdekében Oxygene egy új operátor vezetett be, az úgy nevezett kettőspont-operátort (colon operator), aminek a működése részben megegyezik (.) operátor működésével azzal a különbséggel, hogy ha eredetileg érintett metódus/tag érték típussal tért vissza, akkor (:) operátor használata esetén Nullable<eredeti típus> lesz a visszatérési érték típusa. Ezzel a módosítással (:) operátor Nil-ra inicializált objektumokra is használható úgy, hogy ha objektum Nil, akkor a metódus meghívása nem kivételt eredményez, hanem Nil-lal tér vissza. Pl.:

class method ConsoleApp.Main; var lInt: Integer := 15; lStr: string := nil; begin var s := lInt:ToString; // returns a String var i := lStr:Length; // returns a nullable<Integer> end;

Anonim típusok

A nyelvben lehetőségünk van névtelen osztályokat deklarálni egy metodus törzsében. Például:

var lUser := new class(Name := 'Peter'; Age := 49); Console.WriteLine(lUser.Name+' is '+lUser.Age.ToString+' years old');

Itt osztály tagjainak típusát fordító a nekik adott értékekből következteti ki, de tagok típusa explicit módon is megadható. Az előző példa ekvivalens a következővel:

var lUser := new class(Name: String := 'Peter', Age: Double := 49); Console.WriteLine(lUser.Name+' is ' + lUser.Age + ' years old');

Anonim osztályok tagjainak nevei az inicializáló értékükkel is megadható, például ha más osztály tagjaival inicializáljuk:

var lUser := new class(Data.Name, Data.Value);

Ez a kód olyan anonim osztályt hoz létre, melynek két adattagja van: Name és Value, és a típusuk megegyezik a Data osztály megfelelő adattagjainak a típusával.

Beágyazott (Nested) típusok

Ezek olyan típusok amelyek figyelembe veszik másik típusok tagjait (általában osztályokét vagy rekordokét). A "nasted in" kulcsszóval kell definiálni és utána kell írni a szülő típust. Például:

type Address nested in Person = public class ... end; Gender nested in Person = public enum (Male, Female); ClickEventHandler nested in Button = private delegate ...;

Delegates

Delegate típusú objektumok nem mások, mint a függvények és metódusok mutatói. Biztonságosan használhatóak dinamikus függvények és metódusok meghívására. .NET-ben delegate típusú objektumokat eseményekkel kombinálva használják úgy, hogy egy eseményhez egy vagy több delegate hozzárendelhető.

Az Oxygene nyelvben egy delegate 4 kulcsszóval is deklarálható: function, procedure, method és delegate.

Egy delegált függvény vagy metódus meghívható delegate specifikus metódusok segítségével (BeginInvoke és EndInvoke), de kifejezésként is használhatjuk őket. Pl.:

type MyDelegate = delegate; .. var meth: MyDelegate; begin meth; meth(); end;

Felsorolási típusok

Az enum vagy a flag kulcsszó és a felsorolás neve után kapcsos zárójelben soroljuk fel az értékeket. A flags abban különbözik az enum-tól, hogy a felsorolási típus értékei nem 0,1,2... lesz hanem a kettes számrendszer számait kapják értékül 1,2,4,8,16... Például:

type Color = (Red, Blue, Green); ... MyObject.SurfaceColor := Color.Blue;

A név után opcionálisan megadható a felsorolás típusa (pl: hogy kisebb helyet foglaljon), de ez a típus csak beépített típus lehet, azaz Byte, Sbyte, Int16, Int32, Int64, Uint16, Uint32, Uint64, Char típusok egyike. Illetve az egyes elemekhez rendelt érték.

type Season = enum(Spring, Summer, Fall, Autumn=Fall, Winter) of byte; Color = (Red, Blue=4, Green);

Halmazok

A halmaz típus bír annak a szokásos műveleteivel: in(tartalmazás), +(unió), -(differencia), *(metszet), illetve lehet halmazok egyenlőségét lekérdezni(=), és van halmazok közti <=(részhalmaz), >=(részhalmaz), <>(nem egyenlő) műveletek. A halmaz értékeinek 0-nál nagyobbnak kell lennie! Egy halmazban tárolt elem maximális értéke 0x100000 lehet (azaz 128 kbit-nél nem foglalhat többet egy érték a memóriából). Példa:

Type MySet1 = set of 1000; // set with elements 0..999 MySet2 = set of (Abc, Def, Ghi); // implicit enums

Szükség esetén halmaztípus felsorolási típusból is létrehozható:

type MyEnum = (Abc, Def, Ghi); MySet3 = Set of MyEnum; // minden lehetséges érték benne lesz a halmazban

Egy halmaz érték szerint adódik át paraméterben és következő a szintaxisa:

var x: MySet3 := [MySet.Def, MySet.Abc];

Tömbök

A tömb inicializálódik, ha eleget tesz a következő 3 szabálynak:

  1. A tömb határa definiált (pl az "array[0..] of byte" nem inicializálódik, míg az "array[0..10] of byte" igen )
  2. a tömb mezőként (field) vagy lokális változóként van definiálva
  3. nincsen egy explicit kijelölt inicializáló értéke

Dinamikus (unbound) tömbök.
.NET más nyelveihez hasonlóan tömb mérete értékhez van kötve, nem a típusához. Pl.:

var Array1: array of String; Array2: array of Byte; begin Array1 := new String[25]; // 25 strings 0..24 Arrays2 := new Byte[40]; // 40 arrays of string (nil'ed) …

Kötött (bound) tömbök.
Oxygen-ben lehetőség van a tömbök méreteinek előredefiniálásra. Előre definiált tömbök a kötött tömbök. Pl.:

type StringArray1: array [0..5] of String; StringArray2: array [0..] of String; StringArray3: array [0.., 0..] of String; … var array1: StringArray1; array2: StringArray2; array3: StringArray3; array4: array[0..5] of Integer; begin array1 := new StringArray; // 6 strings 0..5 array2 := new StringArray2(25); // 25 strings 0..24 array1 := new StringArray(45, 12); // 45x12 matrix of strings

Megjegyzés: Nem csak egész típusokat használhatjuk tömb határainak definiálásra, hanem karakter- és felsorolási típusokat is használhatjuk.

Konstans inline tömbök.
Konstans tömbök anélkül is használhatóak, hogy kézzel definiáljuk őket. Pl.:

ListBox.AddRange(['a', 'b']); x := [1,2,3] var x: array of Integer := [1,2];

Statikus tömbök.
Referencia szerint adódnak át paraméterben. Pl.:

var b: ^Byte; begin b[0] = 15; b[1] := 12; end;

Inline tömbök. Nemkonstans inline tömbök csak nembiztonságos kódban (unsafe code) használhatóak.

Rekordok

Nem csak váltózók gyűjteménye mint object pascalban hanem lehetnek benne eljárások is. Az osztályokhoz hasonlóan a rekordok változóinak és metódusainak is lehet megadni láthatóságot (alapértelmezésben: assembly). Szintén az osztályokhoz hasonló tulajdonsága, hogy egy vagy több interfészt is megvalósíthat. Egyetlen eltérés az osztályoktól az, hogy a rekordokból nem származhat más rekord vagy osztály. Például:

type Person = Record method toString: String; override; Forename,Surname: String; Born: Integer; end;

Alapértelmezetten .NET dönti el, hogy a rekord mezői hogy helyezkednek el a memóriában, így több helyet foglalhatnak, mint a bennük foglalt mezőknek szükséges. StructLayout attribútum segítségével a rekord eltárolásra szükséges hely minimalizálható. Pl.:

uses System.Runtime.InteropServices; type [StructLayout(LayoutKind.Sequential, Pack := 1)] MyRecord = record public FieldA: Integer; FieldB: Byte; end;

A példában megmutatott rekord mérete 5 bájt, de ha eltávolítjuk a StructLayout attribútumot, akkor 8 bájt.
Megjegyzés. .NET nem támogat üres rekordokat, így a következő kód hibásnak számít:

type MyRecord = record end;

Ha mégis szükség van rá (például verem-alapú nembiztonságos tömb megvalósításához), akkor implicit méret megadásával mégis definiálható az üres tömb:

type [StructLayout(LayoutType.Explicit, Size := 1028)] MyRecord = record end;

Ha egy rekord nem tartalmaz mezőket, csak metódusokat, akkor üresnek számít és előbb említett attribútum szükséges a deklarálásához.

Osztályok

Viselkedését és lehetőségeit tekintve megfelel a Java és a C# megközelítésének. Részletesebben erről az Objektum-elvű programozás fejezetben lesz szó. Az osztály referencia típus, melynek adattagok, konstruktorok, destruktorok, metódusok, konstansok, propertik, operátorok, indexerek, osztály adattagok lehetnek a deklarációs részében.

type MyClass1 = public class public constructor; virtual; class method TestIt; virtual; end;