A program is constructed from source-code modules called units. Each unit is stored in its own file and compiled separately; compiled units (.DCU files) are linked to create an application. Units allow you to
In traditional Pascal programming, all source code, including the main program, is stored in .PAS files. Delphi uses a project (.DPR) file to store the "main" program, while most other source code resides in unit (.PAS) files. Each application--or project--consists of a single project file and one or more unit files. (Strictly speaking, you needn't explicitly use any units in a project, but all programs automatically use the System unit.) To build a project, the compiler needs either a source file or a previously compiled DCU for each unit.
The program heading specifies a name for the program. The uses clause lists units used by the program. The block contains declarations and statements that are executed when the program runs. The Delphi IDE expects to find these three elements in a single project (.DPR) file.
The example below shows the project file for a program called Editor.
1 program Editor;
2
3 uses
4 Forms,
5 REAbout in 'REABOUT.PAS' {AboutBox},
6 REMain in 'REMain.pas' {MainForm};
7
8 {$R *.RES}
9
10 begin
11 Application.Title := 'Text Editor';
12 Application.CreateForm(TMainForm, MainForm);
13 Application.Run;
14 end.
Line 1 contains the program heading. The uses clause is on lines 3 through 6. Line 8 is a compiler directive that links the project's resource file into the program. Lines 10 through 14 contain the block of statements that are executed when the program runs. Finally, the project file, like all source files, ends with a period.
This is in fact a fairly typical project file. Project files are usually short, since most of a program's logic resides in its unit files. Project files are generated and maintained by Delphi, and it is seldom necessary to edit them manually.
The program heading specifies the program's name. It consists of the reserved word program, followed by a valid identifier, followed by a semicolon. For Delphi applications, the identifier must match the project file name. In the example above, since the program is called Editor, the project file should be called EDITOR.DPR.
In standard Pascal, a program heading can include parameters after the program name:
program Calc(input, output);
Delphi's compiler ignores these parameters.
The uses clause lists units that are incorporated into the program. These units may in turn have uses clauses of their own. For more information about the uses clause, see "Unit references and the uses clause".
The block contains a simple or structured statement that is executed when the program runs. In most Delphi programs, the block consists of a compound statement--bracketed between the reserved words begin and end--whose component statements are simply method calls to the project's Application object. (Every Delphi project has an Application variable that holds an instance of TApplication, TWebApplication, or TServiceApplication.) The block can also contain declarations of constants, types, variables, procedures, and functions; these declarations must precede the statement part of the block.
A unit consists of types (including classes), constants, variables, and routines (functions and procedures). Each unit is defined in its own unit (.PAS) file.
A unit file begins with a unit heading, which is followed by the interface, implementation, initialization, and finalization sections. The initialization and finalization sections are optional. A skeleton unit file looks like this:
unit Unit1;
interface
uses { List of units goes here }
{ Interface section goes here }
implementation
uses { List of units goes here }
{ Implementation section goes here }
initialization
{ Initialization section goes here }
finalization
{ Finalization section goes here }
end.
The unit must conclude with the word end followed by a period.
The unit heading specifies the unit's name. It consists of the reserved word unit, followed by a valid identifier, followed by a semicolon. For Delphi applications, the identifier must match the unit file name. Thus, the unit heading
unit MainForm;
would occur in a source file called MAINFORM.PAS, and the file containing the compiled unit would be MAINFORM.DCU.
Unit names must be unique within a project. Even if their unit files are in different directories, two units with the same name cannot be used in a single program.
The interface section of a unit begins with the reserved word interface and continues until the beginning of the implementation section. The interface section declares constants, types, variables, procedures, and functions that are available to clients--that is, to other units or programs that use the unit where they are declared. These entities are called public because a client can access them as if they were declared in the client itself.
The interface declaration of a procedure or function includes only the routine's heading. The block of the procedure or function follows in the implementation section. Thus procedure and function declarations in the interface section work like forward declarations, although the forward directive isn't used.
The interface declaration for a class must include declarations for all class members.
The interface section can include its own uses clause, which must appear immediately after the word interface. For information about the uses clause, see "Unit references and the uses clause".
The implementation section of a unit begins with the reserved word implementation and continues until the beginning of the initialization section or, if there is no initialization section, until the end of the unit. The implementation section defines procedures and functions that are declared in the interface section. Within the implementation section, these procedures and functions may be defined and called in any order. You can omit parameter lists from public procedure and function headings when you define them in the implementation section; but if you include a parameter list, it must match the declaration in the interface section exactly.
In addition to definitions of public procedures and functions, the implementation section can declare constants, types (including classes), variables, procedures, and functions that are private to the unit--that is, inaccessible to clients.
The implementation section can include its own uses clause, which must appear immediately after the word implementation. For information about the uses clause, see "Unit references and the uses clause".
The initialization section is optional. It begins with the reserved word initialization and continues until the beginning of the finalization section or, if there is no finalization section, until the end of the unit. The initialization section contains statements that are executed, in the order in which they appear, on program start-up. So, for example, if you have defined data structures that need to be initialized, you can do this in the initialization section.
The initialization sections of units used by a client are executed in the order in which the units appear in the client's uses clause.
The finalization section is optional and can appear only in units that have an initialization section. The finalization section begins with the reserved word finalization and continues until the end of the unit. It contains statements that are executed when the main program terminates. Use the finalization section to free resources that are allocated in the initialization section.
Finalization sections are executed in the opposite order from initializations. For example, if your application initializes units A, B, and C, in that order, it will finalize them in the order C, B, and A.
Once a unit's initialization code starts to execute, the corresponding finalization section is guaranteed to execute when the application shuts down. The finalization section must therefore be able to handle incompletely initialized data, since, if a runtime error occurs, the initialization code might not execute completely.
A uses clause lists units used by the program, library, or unit in which the clause appears. (For information about libraries, see "Dynamic-link libraries and packages.") A uses clause can occur in
Most project files contain a uses clause, as do the interface sections of most units. The implementation section of a unit can contain its own uses clause as well.
The System unit is used automatically by every Delphi application and cannot be listed explicitly in the uses clause. (System implements routines for file I/O, string handling, floating point operations, dynamic memory allocation, and so forth.) Other standard library units, such as SysUtils, must be included in the uses clause. In most cases, Delphi places all necessary units in the uses clause when it generates and maintains a source file.
For more information about the placement and content of the uses clause, see "Multiple and indirect unit references" and "Circular unit references".
A uses clause consists of the reserved word uses, followed by one or more comma-delimited unit names, followed by a semicolon. Examples:
uses Forms, Main; uses Windows, Messages, SysUtils, Strings, Classes, Unit2, MyUnit;
In the uses clause of a program or library, any unit name may be followed by the reserved word in and the name of a source file, with or without a directory path, in single quotation marks; directory paths can be absolute or relative. Examples:
uses Windows, Messages, SysUtils, Strings in 'C:\Classes\Strings.pas', Classes; uses Forms, Main, Extra in '..\EXTRA\EXTRA.PAS';
Include in ... after a unit name when you need to specify the unit's source file. Since the Delphi IDE expects unit names to match the names of the source files in which they reside, there is usually no reason to do this. Using in is necessary only when the location of the source file is unclear, for example when
Delphi also relies on the in ... construction to determine which units are part of a project. Only units that appear in a project (.DPR) file's uses clause followed by in and a file name are considered to be part of the project; other units in the uses clause are used by the project without belonging to it. This distinction has no effect on compilation, but it affects IDE tools like the Project Manager and Project Browser.
In the uses clause of a unit, you cannot use in to tell the compiler where to find a source file. Every unit must be in the compiler's search path, Delphi's Library search path, or the same directory as the unit that uses it. Moreover, unit names must match the names of their source files.
The order in which units appear in the uses clause determines the order of their initialization (see "The initialization section") and affects the way identifiers are located by the compiler. If two units declare a variable, constant, type, procedure, or function with the same name, the compiler uses the one from the unit listed last in the uses clause. (To access the identifier from the other unit, you would have to add a qualifier: UnitName.Identifier.)
A uses clause need include only units used directly by the program or unit in which the clause appears. That is, if unit A references constants, types, variables, procedures, or functions that are declared in unit B, then A must use B explicitly. If B in turn references identifiers from unit C, then A is indirectly dependent on C; in this case, C needn't be included in a uses clause in A, but the compiler must still be able to find both B and C in order to process A.
The example below illustrates indirect dependency.
program Prog; uses Unit2; const a = b; ... unit Unit2; interface uses Unit1; const b = c; ... unit Unit1; interface const c = 1; ...
In this example, Prog depends directly on Unit2, which depends directly on Unit1. Hence Prog is indirectly dependent on Unit1. Because Unit1 does not appear in Prog's uses clause, identifiers declared in Unit1 are not available to Prog.
To compile a client module, the compiler needs to locate all units that the client depends on, directly or indirectly. Unless the source code for these units has changed, however, the compiler needs only their .DCU files, not their source (.PAS) files.
When changes are made in the interface section of a unit, other units that depend on it must be recompiled. But when changes are made only in the implementation or other sections of a unit, dependent units don't have to be recompiled. The compiler tracks these dependencies automatically and recompiles units only when necessary.
When units reference each other directly or indirectly, the units are said to be mutually dependent. Mutual dependencies are allowed as long as there are no circular paths connecting the uses clause of one interface section to the uses clause of another. In other words, starting from the interface section of a unit, it must never be possible to return to that unit by following references through interface sections of other units. For a pattern of mutual dependencies to be valid, each circular reference path must lead through the uses clause of at least one implementation section.
In the simplest case of two mutually dependent units, this means that the units cannot list each other in their interface uses clauses. So the following example leads to a compilation error:
unit Unit1; interface uses Unit2; ... unit Unit2; interface uses Unit1; ...
However, the two units can legally reference each other if one of the references is moved to the implementation section:
unit Unit1; interface uses Unit2; ... unit Unit2; interface ... implementation uses Unit1; ...
To reduce the chance of circular references, it's a good idea to list units in the implementation uses clause whenever possible. Only when identifiers from another unit are used in the interface section is it necessary to list that unit in the interface uses clause.
pubsweb@inprise.com
Copyright © 1999, Inprise Corporation. All rights reserved.