Next: , Previous: Variant Records, Up: Type Definition Possibilities

##### 6.2.11.5 EP's Schema Types including String

Schemata are types that depend on one or more variables, called discriminants. They are an ISO 10206 Extended Pascal feature.

```     type
RealArray (n: Integer) = array [1 .. n] of Real;
Matrix (n, m: PositiveInteger) = array [1 .. n, 1 .. m] of Integer;
```

The type RealArray in this example is called a Schema with the discriminant n.

To declare a variable of such a type, write:

```     var
Foo: RealArray (42);
```

The discriminants of every global or local schema variable are initialized at the beginning of the procedure, function or program where the schema variable is declared.

Schema-typed variables “know” about their discriminants. Discriminants can be accessed just like record fields:

```     program Schema1Demo;
type
PositiveInteger = 1 .. MaxInt;
RealArray (n: Integer) = array [1 .. n] of Real;
Matrix (n, m: PositiveInteger) = array [1 .. n, 1 .. m] of Integer;

var
Foo: RealArray (42);

begin
WriteLn (Foo.n)  { yields 42 }
end.
```

Schemata may be passed as parameters. While types of schema variables must always have specified discriminants (which may be other variables), formal parameters (by reference or by value) may be of a schema type without specified discriminant. In this, the actual parameter may posses any discriminant. The discriminants of the parameters get their values from the actual parameters.

Also, pointers to schema variables may be declared without a discriminant:

```     program Schema2Demo;
type
RealArray (n: Integer) = array [1 .. n] of Real;
RealArrayPtr = ^RealArray;
var
Bar: RealArrayPtr;
begin
end.
```

When applying New to such a pointer, you must specify the intended value of the discriminant as a parameter:

```     New (Bar, 137)
```

As a GNU Pascal extension, the above can also be written as

```     Bar := New (RealArrayPtr, 137)
```

The allocated variable behaves like any other schema variable:

```     program Schema3Demo;
type
RealArray (n: Integer) = array [1 .. n] of Real;
RealArrayPtr = ^RealArray;
var
Bar: RealArrayPtr;
i: Integer;
begin
Bar := New (RealArrayPtr, 137);
for i := 1 to Bar^.n do
Bar^[i] := 42
end.
```

Since the schema variable “knows” its size, pointers to schemata can be disposed just like other pointers:

```     Dispose (Bar)
```

Schemata are not limited to arrays. They can be of any type that normally requires constant values in its definition, for instance subrange types, or records containing arrays etc. (Sets do not yet work.)

References to the schema discriminants are allowed, and the `with` statement is also allowed, so one can say:

```     program SchemaWithDemo;
type
RealArray (n: Integer) = array [1 .. n] of Real;
var
MyArray: RealArray (42);
begin
WriteLn (MyArray.n);  { writes 42 }
with MyArray do
WriteLn (n);        { writes 42 }
end.
```

Finally, here is a somewhat exotic example. Here, a ColoredInteger behaves just like an ordinary integer, but it has an additional property Color which can be accessed like a record field.

```     program SchemaExoticDemo;

type
ColorType = (Red, Green, Blue);
ColoredInteger (Color: ColorType) = Integer;

var
Foo: ColoredInteger (Green);

begin
Foo := 7;
if Foo.Color = Red then
Inc (Foo, 2)
else
Foo := Foo div 3
end.
```

An important schema is the predefined String schema (according to Extended Pascal). It has one predefined discriminant identifier `Capacity`. GPC implements the `String` schema as follows:

```     type
String (Capacity: Cardinal) = record
Length: 0 .. Capacity;
Chars: packed array [1 .. Capacity + 1] of Char
end;
```

The `Capacity` field may be directly referenced by the user, the `Length` field is referenced by a predefined string function `Length (Str)` and contains the current string length. `Chars` contains the chars in the string. The `Chars` and `Length` fields cannot be directly referenced by a user program.

If a formal value parameter is of type String (with or without discriminant), the actual parameter may be either a `String` schema, a fixed string (character array), a single character, a string literal or a string expression. If the actual parameter is a String schema, it is copied for the parameter in the usual way. If it is not a schema, a String schema is created automatically, the actual parameter is copied to the new variable and the `Capacity` field of the new variable is set to the length of the actual parameter.

Actual parameters to var parameters of type String must be String schemata, not string literals or character arrays.

```     program StringDemo (Output);

type
SType = String (10);
SPtr  = ^String;

var
Str : SType;
Str2: String (100000);
Str3: String (20) value 'string expression';
DStr: ^String;
ZStr: SPtr;
Len : Integer value 256;
Ch  : Char value 'R';

{ `String' accepts any length of strings }
procedure Foo (z: String);
begin
WriteLn ('Capacity: ', z.Capacity);
WriteLn ('Length  : ', Length (z));
WriteLn ('Contents: ', z);
end;

{ Another way to use dynamic strings }
procedure Bar (SLen: Integer);
var
LString: String (SLen);
FooStr: type of LString;
begin
LString := 'Hello world!';
Foo (LString);
FooStr := 'How are you?';
Foo (FooStr);
end;

begin
Str  := 'KUKKUU';
Str2 := 'A longer string variable';
New (DStr, 1000);  { Select the string Capacity with `New' }
DStr^ := 'The maximum length of this is 1000 chars';
New (ZStr, Len);
ZStr^ := 'This should fit here';
Foo (Str);
Foo (Str2);
Foo ('This is a constant string');
Foo ('This is a ' + Str3);
Foo (Ch);  { A char parameter to string routine }
Foo ('');  { An empty string }
Foo (DStr^);
Foo (ZStr^);
Bar (10000);
end.
```

In the above example, the predefined procedure `New` was used to select the capacity of the strings. Procedure `Bar` also has a string whose size depends of the parameter passed to it and another string whose type will be the same as the type of the first string, using the `type of` construct.

All string and character types are compatible as long as the destination string is long enough to hold the source in assignments. If the source string is shorter than the destination, the destination is automatically blank padded if the destination string is not of string schema type.