Types

When you declare a variable, you must state its type. A variable’s type circumscribes the set of values it can have and the operations that can be performed on it. A type declaration specifies the identifier that denotes a type.

Types - 图1type declaration

When an identifier occurs on the left side of a type declaration, it’s declared as a type identifier for the block in which the type declaration occurs. A type identifier’s scope doesn’t include itself except for pointer types.

type

There are six major type classes. They are described in the following sections.

Simple types

Simple types define ordered sets of values.

simple type

real type

A real type identifier is one of the standard identifiers: Real, Single, Double, Extended, or Comp. Chapter 1 explains how to denote constant integer type and real type values.

Ordinal types

Ordinal types are a subset of simple types. All simple types other than real types are ordinal types, which are set off by six characteristics:

  • All possible values of a given ordinal type are an ordered set, and

    each possible value is associated with an ordinality, which is an integral value. Except for integer type values, the first value of every ordinal type has ordinality 0, the next has ordinality 1, and so on for each value in that ordinal type. The ordinality of an integer type value is the value itself. In any ordinal type, each value other than the first has a predecessor, and each value other than the last has a successor based on the ordering of the type.

  • The standard function Ord can be applied to any ordinal type value

    to return the ordinality of the value.

  • The standard function Pred can be applied to any ordinal type

    value to return the predecessor of the value. If applied to the first value in the ordinal type and if range checking is enabled {$R+}, Pred produces a run-time error.

  • The standard function Succ can be applied to any ordinal type

    value to return the successor of the value. If applied to the last value in the ordinal type and if range checking is enabled {$R+}, Succ produces a run-time error.

  • The standard function Low can be applied to an ordinal type

    identifier and to a variable reference of an ordinal type. The result is the lowest value in the range of the given ordinal type.

  • The standard function High can be applied to an ordinal type

    identifier and to a variable reference of an ordinal type. The result is the highest value in the range of the given ordinal type.

The syntax of an ordinal type follows:

ordinal type

Object Pascal has twelve predefined ordinal types: Integer, Shortint, Smallint, Longint, Byte, Word, Cardinal, Boolean, ByteBool, WordBool, LongBool, and Char. In addition, there are two other classes of user-defined ordinal types: enumerated types and subrange types.

Integer types

Object Pascal's predefined integer types are divided into two categories: fundamental types and generic types. The range and format of the fundamental types is independent of the underlying CPU and operating system and does not change

across different implementations of Object Pascal. The range and format of the generic types, on the other hand, depends on the underlying CPU and operating system.

The fundamental integer types are Shortint, Smallint, Longint, Byte, and Word. Each fundamental integer type denotes a specific subset of the whole numbers, according to the following table:

Table 3-1 Fundamental integer types

Type

Range

Format

Shortint

-128..127

Signed 8-bit

Smallint

-32768..32767

Signed 16-bit

Longint

-2147483648..2147483647

Signed 32-bit

Byte

0..255

Unsigned 8-bit

Word

0..65535

Unsigned 16-bit

The generic integer types are Integer and Cardinal. The Integer type represents a generic signed integer, and the Cardinal type represents a generic unsigned integer. The actual ranges and storage formats of the Integer and Cardinal vary across different implementations of Object Pascal, but are generally the ones that result in the most efficient integer operations for the underlying CPU and operating system.

Table 3-2 Generic integer types for 16-bit implementations of Object Pascal

Type

Range

Format

Integer

-32768..32767

Signed 16-bit

Cardinal

0..65535

Unsigned 16-bit

Table 3-3 Generic integer types for 32-bit implementations of Object Pascal

Type

Range

Format

Integer

-2147483648..2147483647

Signed 32-bit

Cardinal

0..2147483647

Unsigned 32-bit

Applications should use the generic integer formats whenever possible, since they generally result in the best performance for the underlying CPU and operating system. The fundamental integer types should be used only when the actual range and/or storage format matters to the application.

Arithmetic operations with integer-type operands use 8-bit, 16-bit, or 32-bit precision, according to the following rules:

  • The type of an integer constant is the predefined integer type with

    the smallest range that includes the value of the integer constant.

  • For a binary operator (an operator that takes two operands), both

    operands are converted to their common type before the operation. The common type is the predefined integer type with the smallest range that includes all possible values of both types. For example, the common type of Smallint and Byte is Smallint, and the common type of Smallint and Word is Longint. The operation is performed using the precision of the common type, and the result type is the common type.

  • The expression on the right of an assignment statement is evaluated

    independently from the size or type of the variable on the left.

  • Any byte-sized operand is converted to an intermediate word-sized

    operand that is compatible with both Smallint and Word before any arithmetic operation is performed.

An integer-type value can be explicitly converted to another integer type through typecasting. Typecasting is described in Chapters 4 and 5.

Boolean types

There are four predefined boolean types: Boolean, ByteBool, WordBool, and LongBool. Boolean values are denoted by the predefined constant identifiers False and True.

Because booleans are enumerated types, these relationships hold:

  • False < True

  • Ord(False) = 0

  • Ord(True) = 1

  • Succ(False) = True

  • Pred(True) = False

Boolean and ByteBool variables occupy one byte, a WordBool variable occupies two bytes (one word), and a LongBool variable occupies four bytes (two words). Boolean is the preferred type and uses the least memory; ByteBool, WordBool, and LongBool primarily exist to provide compatibility with other languages and the Windows environment.

A Boolean variable can assume the ordinal values 0 and 1 only, but variables of type ByteBool, WordBool, and LongBool can assume other ordinal values. An expression of type ByteBool, WordBool, or LongBool is considered False when its ordinal value is zero, and True when its ordinal value is nonzero. Whenever a ByteBool, WordBool, or LongBool value is used in a context where a Boolean value is expected, the compiler will automatically generate code that converts any nonzero value to the value True.

Char type

Char’s set of values are characters, ordered according to the extended ASCII character set. The function call Ord(Ch), where Ch is a Char value, returns Ch’s ordinality.

A string constant of length 1 can denote a constant character value. Any character value can be generated with the standard function Chr.

Enumerated types

Enumerated types define ordered sets of values by enumerating the identifiers that denote these values. Their ordering follows the sequence the identifiers are enumerated in.

Types - 图2Types - 图3enumerated type

Types - 图4identifier list

When an identifier occurs within the identifier list of an enumerated type, it’s declared as a constant for the block the enumerated type is declared in. This constant’s type is the enumerated type being declared.

An enumerated constant’s ordinality is determined by its position in the identifier list it’s declared in. The enumerated type it’s declared in becomes the constant’s type. The first enumerated constant in a list has an ordinality of zero.

Here’s an example of an enumerated type:

type

Suit = (Club, Diamond, Heart, Spade);

Given these declarations, Diamond is a constant of type Suit.

When the Ord function is applied to an enumerated type’s value, Ord returns an integer that shows where the value falls with respect to the other values of the enumerated type. Given the preceding declarations, Ord(Club) returns zero, Ord(Diamond) returns 1, and so on.

Subrange types

A subrange type is a range of values from an ordinal type called the host type. The definition of a subrange type specifies the smallest and the largest value in the subrange; its syntax follows:

Types - 图5subrange type

Both constants must be of the same ordinal type. Subrange types of the form A..B

require that A is less than or equal to B.

These are examples of subrange types:

0..99

-128..127

Club..Heart

A variable of a subrange type has all the properties of variables of the host type, but its run-time value must be in the specified interval.

One syntactic ambiguity arises from allowing constant expressions where Standard Pascal only allows simple constants. Consider the following declarations:

const

X = 50;

Y = 10;

type

Color = (Red, Green, Blue);

Scale = (X - Y) * 2..(X + Y) * 2;

Standard Pascal syntax dictates that, if a type definition starts with a parenthesis, it’s an enumerated type, such as the Color type in the previous example. The intent of the declaration of scale is to define a subrange type, however. The solution is to reorganize the first subrange expression so that it doesn’t start with a parenthesis, or to set another constant equal to the value of the expression and use that constant in the type definition:

type

Scale = 2 * (X - Y)..(X + Y) * 2;

Real types

A real type has a set of values that is a subset of real numbers, which can be represented in floating-point notation with a fixed number of digits. A value’s floating-point notation normally comprises three values—M, B, and E—such that M x BE = N, where B is always 2, and both M and E are integral values within the real type’s range. These M and E values further prescribe the real type’s range and precision.

There are five kinds of real types: Real, Single, Double, Extended, and Comp. The real types differ in the range and precision of values they hold as shown in the following table:

Table 3-4 Real data types

Type

Range

Significant digits

Size in bytes

Real

2.9 x 10-39 .. 1.7 x 1038

11-12

6

Single

1.5 x 10-45 .. 3.4 x 1038

7-8

4

Double

5.0 x 10-324 .. 1.7 x 10308

15-16

8

Extended

3.4 x 10-4932 .. 1.1 x 104932

19-20

10

Comp

-263+1 .. 263 -1

19-20

8

The Comp type holds only integral values within -263+1 to 263 -1, which is approximately -9.2 x 1018 to 9.2 x 1018.

Object Pascal supports two models of code generation for performing real-type operations: software floating point and 80x87 floating point. The $N compiler directive is used to select the appropriate model.

80x87 floating point

In the {$N+} state, which is selected by default, the generated code performs all real- type calculations using 80x87 instructions and can use all five real types. For more details on 80x87 floating-point code generation, refer to Chapter 14, “Using the 80x87.”

Software floating point

In the {$N-} state, the generated code performs all real-type calculations in software by calling run-time library routines. For reasons of speed and code size, only operations on variables of type Real are allowed in this state. Any attempt to compile statements that operate on the Single, Double, Extended, and Comp types generates an error.

Note The Delphi Visual Class Library requires that you compile your applications in the

{$N+} state. Unless you are compiling an application that doesn't use VCL, you should refrain from using the {$N–} state.

String types

A string-type value is a sequence of characters with a dynamic length attribute (depending on the actual character count during program execution), and a constant size attribute from 1 to 255. A string type declared without a size attribute is given the default size attribute 255. The length attribute’s current value is returned by the standard function Length. Operators for the string types are described in the sections “String operator” and “Relational operators” in Chapter 5.

Types - 图6string type

The ordering between any two string values is set by the ordering relationship of the character values in corresponding positions. In two strings of unequal length, each character in the longer string without a corresponding character in the shorter string takes on a higher or greater-than value; for example, ‘xs’ is greater than ‘x’. Null strings can be equal only to other null strings, and they hold the least string values.

Characters in a string can be accessed as components of an array. See “Arrays, strings, and indexes” on page 32.

The Low and High standard functions can be applied to a string-type identifier and to a variable reference of a string type. In this case, Low returns zero, and High returns the size attribute (maximum length) of the given string.

A variable parameter declared using the OpenString identifier, or using the string keyword in the {$P+} state, is an open string parameter. Open string parameters allow string variables of varying sizes to be passed to the same procedure or function.

Read about open string parameters on page 78.

Structured types

A structured type, characterized by its structuring method and by its component type(s), holds more than one value. If a component type is structured, the resulting structured type has more than one level of structuring. A structured type can have unlimited levels of structuring, but the maximum permitted size of any structured type in Object Pascal is 65,520 bytes.

structured type

In Standard Pascal, the word packed in a structured type’s declaration tells the compiler to compress data storage, even at the cost of diminished access to a

component of a variable of this type. In Object Pascal, however, packed has no effect; instead packing occurs automatically whenever possible.

Class types and class reference types are the cornerstones of object oriented programming in Object Pascal. They are described in full in Chapter 9, "Classes".

Array types

Arrays have a fixed number of components of one type—the component type. In the following syntax diagram, the component type follows the word of.

Types - 图7array type

index type

The index types, one for each dimension of the array, specify the number of elements. Valid index types are all ordinal types except Longint and subranges of Longint. The array can be indexed in each dimension by all values of the corresponding index type; therefore, the number of elements is the product of the number of values in each index type.

The following is an example of an array type:

array[1..100] of Real

If an array type’s component type is also an array, you can treat the result as an array of arrays or as a single multidimensional array. For example,

array[Boolean] of array[1..10] of array[Size] of Real

is interpreted the same way by the compiler as

array[Boolean,1..10,Size] of Real

You can also express

packed array[1..10] of packed array[1..8] of Boolean

as

packed array[1..10,1..8] of Boolean

You access an array’s components by supplying the array’s identifier with one or more indexes in brackets. See “Arrays, strings, and indexes” on page 32.

When applied to an array-type identifier or a variable reference of an array type, the Low and High standard functions return the low and high bounds of the index type of the array.

An array type of the form

packed array[M..N] of Char

where M is less than N is called a packed string type (the word packed can be omitted because it has no effect in Object Pascal). A packed string type has certain properties

not shared by other array types, as explained below. See “Identical and compatible types” on page 24.

An array type of the form

array[0..X] of Char

where X is a positive nonzero integer is called a zero-based character array. Zero-based character arrays are used to store null-terminated strings, and when the extended syntax is enabled (using a {$X+} compiler directive), a zero-based character array is compatible with a PChar value. For a complete discussion of this topic, read Chapter 15, “Using null-terminated strings,” beginning on page 153.

A parameter declared using the array of T syntax is an open array parameter. Open array parameters allow arrays of varying sizes to be passed to the same procedure or function. Read about open array parameters on page 79.

Record types

A record type comprises a set number of components, or fields, that can be of different types. The record-type declaration specifies the type of each field and the identifier that names the field.

record type

field list

Types - 图8

Types - 图9fixed part :

;

The fixed part of a record type sets out the list of fixed fields, giving an identifier and a type for each. Each field contains information that is always retrieved in the same way.

The following is an example of a record type:

type

TDateRec = record Year: Integer; Month: 1..12;

Day: 1..31;

end;

The variant part shown in the syntax diagram of a record-type declaration distributes memory space for more than one list of fields, so the information can be accessed in more ways than one. Each list of fields is a variant. The variants overlay the same space in memory, and all fields of all variants can be accessed at all times.

Types - 图10

tag field type

Types - 图11variant

You can see from the diagram that each variant is identified by at least one constant. All constants must be distinct and of an ordinal type compatible with the tag field type. Variant and fixed fields are accessed the same way.

An optional identifier, the tag field identifier, can be placed in the variant part. If a tag field identifier is present, it becomes the identifier of an additional fixed field—the tag field—of the record. The program can use the tag field’s value to show which variant is active at a given time. Without a tag field, the program selects a variant by another criterion.

Some record types with variants follow:

type

TPerson = record

FirstName, LastName: string[40]; BirthDate: TDate;

case Citizen: Boolean of

True: (BirthPlace: string[40]); False: (Country: string[20];

EntryPort: string[20]; EntryDate: TDate; ExitDate: TDate);

end;

TPolygon = record

X, Y: Real;

case Kind: Figure of

TRectangle: (Height, Width: Real); TTriangle: (Side1, Side2, Angle: Real); TCircle: (Radius: Real);

end;

Set types

A set type’s range of values is the power set of a particular ordinal type (the base type). The power set is the set of all possible subsets of values of the base type including the empty set. Therefore, each possible value of a set type is a subset of the possible values of the base type.

A variable of a set type can hold from none to all the values of the set. Set-type operators are described in the section “Set operators” in Chapter 5. “Set constructors” in the same chapter shows how to construct set values.

Types - 图12set type

The base type must not have more than 256 possible values, and the ordinal values of the upper and lower bounds of the base type must be within the range 0 to 255.

Every set type can hold the value [ ], which is called the empty set.

File types

A file type consists of a linear sequence of components of the component type, which can be of any type except a file type, any structured type with a file-type component, or an object type. The number of components isn’t set by the file-type declaration.

Types - 图13file type

If the word of and the component type are omitted, the type denotes an untyped file. Untyped files are low-level I/O (input/output) channels primarily used for direct access to any disk file regardless of its internal format.

The standard file type Text signifies a file containing characters organized into lines. Text files use special I/O procedures, which are discussed in Chapter 13, “Input and output.”

Pointer types

A pointer type defines a set of values that point to dynamic variables of a specified type called the base type. A pointer-type variable contains the memory address of a dynamic variable.

Types - 图14pointer type

base type

If the base type is an undeclared identifier, it must be declared in the same type declaration part as the pointer type.

You can assign a value to a pointer variable with the New procedure, the @ operator, the Ptr function, or the GetMem procedure. New allocates a new memory area in the application heap for a dynamic variable and stores the address of that area in the pointer variable. The @ operator directs the pointer variable to the memory area containing any existing variable or procedure or function entry point, including variables that already have identifiers. Ptr points the pointer variable to a specific memory address. GetMem creates a new dynamic variable of a specified size, and puts the address of the block in the pointer variable.

The reserved word denotes a pointer-valued constant that doesn’t point to anything.

Type Pointer

The predefined type Pointer denotes an untyped pointer; that is, a pointer that doesn’t point to any specific type. Variables of type Pointer can’t be dereferenced; writing the pointer symbol ^ after such a variable is an error. Generic pointers, however, can be typecast to allow dereferencing. Like the value denoted by the word nil, values of type Pointer are compatible with all other pointer types. For the syntax of referencing the dynamic variable pointed to by a pointer variable, see Chapter 4’s section entitled “Pointers and dynamic variables” on page 33.

Type PChar

Object Pascal has a predefined type, PChar, to represent a pointer to a null- terminated string. The System unit declares PChar as

type PChar = ^Char;

Object Pascal supports a set of extended syntax rules to facilitate handling of null- terminated strings using the PChar type. For a complete discussion of this topic, see Chapter 15, “Using null-terminated strings.”

Procedural types

Object Pascal allows procedures and functions to be treated as entities that can be assigned to variables and passed as parameters. Such actions are made possible through procedural types.

procedural type

procedure

function

of object

:

The syntax for a procedural-type declaration is the same as a that of a procedure or function header, except that the identifier after the procedure or function keyword is omitted.

There are two categories of procedural types: Global procedure pointers and method pointers.

Global procedure pointers

A procedural type declared without the of object clause is called a global procedure pointer. A global procedure pointer can reference a global procedure or function, and is encoded as a pointer that stores the address of a global procedure or function. Some examples of global procedure pointer types follow:

type

TProcedure = procedure;

TStrProc = procedure(const S: string);

TMathFunc = function(X: Double): Double;

Method pointers

A procedural type declared with the of object clause is called a method pointer. A method pointer can reference a procedure or function method of an object, and is encoded as two pointers. The first pointer stores the address of a method, and the second pointer stores a reference to the object that the method belongs to. Some examples of method pointer types follow:

type

TMethod = procedure of object;

TNotifyEvent = procedure(Sender: TObject) of object;

Procedural values

A variable of a procedural type can be assigned a procedural value. Procedural values can be one of the following:

  • The value nil

  • A variable reference of a procedural type

  • A global procedure or function identifier

  • A method designator

In the context of procedural values, a global procedure or function identifier denotes a global procedure pointer value, and a method designator denotes a method pointer value. For example, given the following declarations:

type

TMainForm = class(TForm)

procedure ButtonClick(Sender: TObject);

...

end;

var

MainForm: TMainForm;

MathFunc: TMathFunc;

OnClick: TNotifyEvent;

function Tan(Angle: Double): Double; far; begin

Result := Sin(Angle) / Cos(Angle);

end;

The variables MathFunc and OnClick can be assigned values as follows:

MathFunc := Tan;

OnClick := MainForm.ButtonClick;

and calls can be made using MathFunc and OnClick as follows:

X := MathFunc(X); { Equivalent to X := Tan(X) }

OnClick(Self); { Equivalent to MainForm.ButtonClick(Self) }

Using a procedural variable that contains the value nil in a procedure statement or function call results in an error. The value nil is intended to indicate that a procedural variable is unassigned, and whenever there is a possibility that a procedural value is nil, procedure statements or function calls involving that procedural variable should be guarded by a test:

if Assigned(OnClick) then OnClick(Self);

The Assigned standard function returns True if the given procedural variable has been assigned a procedural value, or False if the procedural variable contains nil.

Procedural type compatibility

To be considered compatible, procedural types must have the same number of parameters, and parameters in corresponding positions must be of identical types. Finally, the result types of functions must be identical. Parameter names have no significance when determining procedural-type compatibility.

The value nil is compatible with any procedural type.

Global procedure pointer types and method pointer types are always mutually incompatible. In other words, a global procedure or function cannot be assigned to a method pointer variable, and a method cannot be assigned to a global procedure pointer variable.

To be used as procedural values, global procedures and functions must be declared with a far directive or compiled in the {$F+} state. Also, standard procedures and functions, nested procedures and functions, and inline procedures and functions can’t be used as procedural values.

Standard procedures and functions are the ones declared by the System unit, such as WriteLn, ReadLn, Chr, and Ord. To use a standard procedure or function as a procedural value, write a “shell” around it. For example, the following function FSin is assignment-compatible with the TMathFunc type declared above.

function FSin(X: Real): Real; far; begin

FSin := Sin(X);

end;

A procedure or function is nested when it’s declared within another procedure or function. Such nested procedures and functions can’t be used as procedural values.

Identical and compatible types

Two types can be the same, and this sameness (identity) is mandatory in some contexts. At other times, the two types need only be compatible or merely assignment-compatible. They are identical when they are declared with, or their definitions stem from, the same type identifier.

Type identity

Type identity is required only between actual and formal variable parameters in procedure and function calls.

Two types—say, T1 and T2—are identical if one of the following is true: T1 and T2

are the same type identifier; T1 is declared to be equivalent to a type identical to T2.

The second condition connotes that T1 doesn’t have to be declared directly to be equivalent to T2. The type declarations

T1 = Integer;

T2 = T1;

T3 = Integer;

T4 = T2;

result in T1, T2, T3, T4, and Integer as identical types. The type declarations

T5 = set of Char;

T6 = set of Char;

don’t make T5 and T6 identical because set of Char isn’t a type identifier. Two variables declared in the same declaration, for example,

V1, V2: set of Char;

are of identical types—unless the declarations are separate. The declarations

V1: set of Char; V2: set of Char; V3: Integer;

V4: Integer;

mean V3 and V4 are of identical type, but not V1 and V2.

Type compatibility

Compatibility between two types is sometimes required, such as in expressions or in relational operations. Type compatibility is important, however, as a precondition of assignment compatibility.

Type compatibility exists when at least one of the following conditions is true:

  • Both types are the same.

  • Both types are real types.

  • Both types are integer types.

  • One type is a subrange of the other.

  • Both types are subranges of the same host type.

  • Both types are set types with compatible base types.

  • Both types are packed string types with an identical number of

    components.

  • One type is a string type and the other is either a string type,

    packed string type, or Char type.

  • One type is Pointer and the other is any pointer type.

  • Both types are class types or class reference types, and one type is

    derived from the other.

  • One type is PChar and the other is a zero-based character array of

    the form

array[0..X] of Char. (This applies only when extended syntax is enabled with the

{$X+} directive.)

  • Both types are pointers to identical types. (This applies only when

    type-checked pointers are enabled with the {$T+} directive.)

  • Both types are procedural types with identical result types, an

    identical number of parameters, and a one-to-one identity between parameter types.

Assignment compatibility

Assignment compatibility is necessary when a value is assigned to something, such as in an assignment statement or in passing value parameters.

A value of type T2 is assignment-compatible with a type T1 (that is, T1 := T2 is allowed) if any of the following are true:

  • T1 and T2 are identical types and neither is a file type or a

    structured type that contains a file-type component at any level of structuring.

  • T1 and T2 are compatible ordinal types, and the values of type

    T2 falls within the range of possible values of T1 .

  • T1 and T2 are real types, and the value of type T2 falls

    within the range of possible values of T1.

  • T1 is a real type, and T2 is an integer type.

  • T1 and T2 are string types.

  • T1 is a string type, and T2 is a Char type.

  • T1 is a string type, and T2 is a packed string type.

  • T1 and T2 are compatible, packed string types.

  • T1 and T2 are compatible set types, and all the members of the value of type T2

fall within the range of possible values of T1 .

  • T1 and T2 are compatible pointer types.

  • T1 is a class type and T2 is a class type derived from T1.

  • T1 is a class reference type and T2 is a class reference type

    derived from T1.

  • T1 is a PChar and T2 is a string constant. (This applies only

    when extended syntax is enabled {$X+}.)

  • T1 is a PChar and T2 is a zero-based character array of the

    form array[0..X] of

Char. (This applies only when extended syntax is enabled {$X+}.)

  • T1 and T2 are compatible procedural types.

  • T1 is a procedural type, and T2 is a procedure or function with an identical result type, an identical number of parameters, and a one-to-one identity between parameter types.

A compile-time error occurs when assignment compatibility is necessary and none of the items in the preceding list are true.

The type declaration part

Programs, procedures, functions, and methods that declare types have a type declaration part. This is an example of a type declaration part:

type

TRange = Integer;

TNumber = Integer;

TColor = (Red, Green, Blue); TCharVal = Ord('A')..Ord('Z'); TTestIndex = 1..100;

TTestValue = -99..99;

TTestList = array[TTestIndex] of TTestValue; PTestList = ^TTestList;

TDate = class Year: Integer; Month: 1..12;

Day: 1..31;

procedure SetDate(D, M, Y: Integer);

function ShowDate: String;

end;

TMeasureData = record When: TDate; Count: TTestIndex; Data: PTestList;

end;

TMeasureList = array[1..50] of TMeasureData; TName = string[80];

TSex = (Male, Female); PPersonData = ^TPersonData; TPersonData = record

Name, FirstName: TName; Age: Integer;

Married: Boolean;

TFather, TChild, TSibling: PPersonData;

case S: TSex of

Male: (Bearded: Boolean); Female: (Pregnant: Boolean);

end;

TPersonBuf = array[0..SizeOf(TPersonData)-1] of Byte; TPeople = file of TPersonData;

In the example, TRange, TNumber, and Integer are identical types. TTestIndex is compatible and assignment-compatible with, but not identical to, the types TNumber, TRange, and Integer. Notice the use of constant expressions in the declarations of TCharVal and TPersonBuf.

C h a p t e r