Programs and units

Program syntax

A Object Pascal program consists of a program heading, an optional uses clause, and a block.

Programs and units - 图1

The program heading

The program heading specifies the program’s name and its parameters.

Programs and units - 图2program heading

program parameters

The program heading, if present, is ignored by the compiler.

The uses clause

The uses clause identifies all units used by the program.

Programs and units - 图3uses clause

The System unit is always used automatically. System implements all low-level, run- time routines to support such features as file input and output (I/O), string handling, floating point, dynamic memory allocation, and others.

Apart from System, Object Pascal implements many standard units that aren’t used automatically; you must include them in your uses clause. For example,

uses SysUtils; { Can now use SysUtils }

The order of the units listed in the uses clause determines the order of their initialization (see “The initialization part” on page 125).

Note To find the unit file containing a compiled unit, the compiler truncates the unit name listed in the uses clause to the first eight characters and adds the file extension. The file extension for Delphi units is .DCU.

Unit syntax

Units are the basis of in Object Pascal. They’re used to create libraries you can include in various programs without making the source code available, and to divide large programs into logically related modules.

unit

Programs and units - 图4 Programs and units - 图5

The unit heading

The unit heading specifies the unit’s name.

unit heading

The unit name is used when referring to the unit in a uses clause. The name must be unique: Two units with the same name can’t be used at the same time.

Note The name of a unit’s source file and binary file must be the same as the unit identifier, truncated to the first eight characters. If this isn’t the case, the compiler can’t find the source and/or binary file when compiling a program or unit that uses the unit.

The interface part

The interface part declares constants, types, variables, procedures, and functions that are public; that is, available to the host (the program or unit using the unit). The host can access these entities as if they were declared in a block that encloses the host.

interface part

Programs and units - 图6procedure and function heading part

procedure heading ;

;

Unless a procedure or function is inline, the interface part only lists the procedure or function heading. The block of the procedure or function follows in the implementation part.

The implementation part

The implementation part defines the block of all public procedures and functions. In addition, it declares constants, types, variables, procedures, and functions that are private; that is, not available to the host.

implementation part

In effect, the procedure and function declarations in the interface part are like forward declarations, although the forward directive isn’t specified. Therefore, these procedures and functions can be defined and referenced in any sequence in the implementation part.

Note Procedure and function headings can be duplicated from the interface part. You don’t have to specify the formal parameter list, but if you do, the compiler will issue a compile-time error if the interface and implementation declarations don’t match.

The initialization part

The initialization part is the last part of a unit. It consists either of the reserved word end (in which case the unit has no initialization code) or of the reserved word initialization, followed by a list of statements which initialize the unit, followed by the reserved word end.

Programs and units - 图7initialization part

The initialization parts of units used by a program are executed in the same order that the units appear in the uses clause.

Indirect unit references

The uses clause in a module (program or unit) need only name the units used directly by that module. Consider the following:

program Prog; uses Unit2; const a = b; begin

end.

unit Unit2; interface uses Unit1; const b = c; implementation end.

unit Unit1; interface const c = 1; implementation const d = 2; end.

In the previous example, Unit2 is directly dependent on Unit1 and Prog is directly dependent on Unit2. Also, Prog is indirectly dependent on Unit1 (through Unit2), even though none of the identifiers declared in Unit1 are available to Prog.

To compile a module, the compiler must be able to locate all units the module depends upon, directly or indirectly. So, to compile Prog, the compiler must be able to locate both Unit1 and Unit2, or else an error occurs.

Note for C and other language users: The uses clauses of an Object Pascal program provide the “make” logic information traditionally found in make or project files of other languages. With the uses clause, Object Pascal can build all the dependency information into the module itself and reduce the chance for error.

When changes are made in the interface part of a unit, other units using the unit must be recompiled. If you use Make or Build, the compiler does this for you automatically. If changes are made only to the implementation or the initialization part, however, other units that use the unit don’t have to be recompiled. In the previous example, if the interface part of Unit1 is changed (for example, c = 2) Unit2 must be recompiled; changing the implementation part (for example, d = 1) doesn’t require recompilation of Unit2.

Object Pascal can tell when the interface part of a unit has changed by computing a unit version number when the unit is compiled. In the preceding example, when Unit2 is compiled, the current version number of Unit1 is saved in the compiled version of

Unit2. When Prog is compiled, the version number of Unit1 is checked against the version number stored in Unit2. If the version numbers don’t match (indicating that a change was made in the interface part of Unit1 because Unit2 was compiled), the compiler reports an error or recompiles Unit2, depending on the mode of compilation.

Circular unit references

When two or more units reference each other in their uses clauses, the units are said to be mutually dependent. Any pattern of mutual dependencies is allowed as long as there are no circular references created by following the uses clauses in the interface parts of the units. In other words, for any given set of mutually dependent units, starting with the uses clause of the interface part of any unit it must not be possible to return to that unit by following references in the uses clauses of the interface parts. For a pattern of mutual dependencies to be valid, each circular reference path must lead through the uses clause of the implementation part of at least one unit.

In the simplest case of two mutually dependent units, the implication of the above rule is that it is not possible for both units to reference the other in the interface part. It is however possible for one of the units to reference the other in the interface part, as long as the other references the first in the implementation part.

When the compiler detects an invalid circular reference path, it reports error 68, "Circular unit reference". In order to reduce the chances of invalid circular references occurring, it is recommended that a unit use other units in the implementation part whenever possible. Only when symbols from another unit are needed in the interface part should that unit be listed in the interface part uses clause.

C h a p t e r