0% found this document useful (0 votes)
13 views

Cha 02

Uploaded by

skamelrech2020
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

Cha 02

Uploaded by

skamelrech2020
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

01: Coding in Pascal - 39

uses
unitD, unitE;

// hidden global variable


var
PartialTotal: Integer;

// all the exported functions must be coded


procedure MyProc;
begin
// ... code of procedure MyProc
end;

initialization
// optional initialization code

finalization
// optional clean-up code

end.
The purpose of the interface part of a unit is to make details of what the unit con-
tains and can do to programs and other units that will make use of the unit. Whereas
the implementation part contains the nuts and bolts of the unit which are hidden
from outside viewers. This is how Object Pascal can provide this so called encapsula-
tion even without using classes and objects.
As you can see, the interface of a unit can declare a number of different elements,
including procedures, functions, global variables, and data types. Data types are
generally used the most. The IDE automatically places a new class data type in a unit
each time you create a visual form. However, containing form definitions is certainly
not the only use for units in Object Pascal. You can have code only units, with func-
tions and procedures (in a traditional way) and with classes that do not refer to
forms or other visual elements.
Within an interface or an implementation section, the declarations for types, vari-
ables, constants, and the like can be written in any order and can be repeated
multiple times. You can have a few constants, some types, then more constants,
other variables, and another types section. The only rule is that to refer to a symbol
this needs to be declared before it is referenced, which is the reason you often need
to have multiple sections.

The Uses Clause


The uses clause at the beginning of the interface section indicates which other units
we need to access in the interface portion of the unit. This includes the units that
define the data types we refer to in the definition of data types of this unit, such as
the components used within a form we are defining.

Marco Cantù, Object Pascal Handbook


40 - 01: Coding in Pascal

The second uses clause, at the beginning of the implementation section, indicates
additional units we need to access only in the implementation code. When you need
to refer to other units from the code of the routines and methods, you should add
elements in this second uses clause instead of the first one. All the units you refer to
must be present in the project directory or in a directory of the search path.

tip You can set the Search Path for a project in the Project Options. The system also considers units in
the Library path, which is a global setting of the IDE.

C++ programmers should be aware that the uses statement does not correspond to
an include directive. The effect of a uses statement is to import just the pre-compiled
interface portion of the units listed. The implementation portion of the unit is con-
sidered only when that unit is compiled. The units you refer to can be both in source
code format (PAS) or compiled format (DCU).
Although seldom used, Object Pascal had also an $INCLUDE compiler directive that
works similarly to C/C++ includes. These special include files are used by some
libraries for sharing compiler directives or other settings among multiple units, and
generally have the INC file extension. This directive is covered shortly at the end of
this chapter.

note Notice that compiled units in Object Pascal are compatible only if they are build with the same
version of the compiler and system libraries. A unit compiled in an older version of the product is
generally not compatible with a later version of the compiler.

Units and Scope


In Object Pascal units are the key to encapsulation and visibility and, in that sense,
they are probably even more important than the private and public keywords of a
class. The scope of an identifier (such as a variable, procedure, function, or a data
type) is the portion of the code in which the identifier is accessible or visible. The
basic rule is that an identifier is meaningful only within its scope—that is, only
within the unit, function, or procedure in which it is declared. You cannot use an
identifier outside its scope.

note Unlike C or C++, Object Pascal doesn't have the concept of a generic code block that can include a
declaration. While you can use begin and end to create a compound statement, this isn't like a C or
C++ block with curly braces that has its own scope for internally declared variables.

Marco Cantù, Object Pascal Handbook


01: Coding in Pascal - 41

In general, an identifier is visible only after it is defined. There are techniques in the
language that allow declaring an identifier before its complete definition, but the
general rule still applies if we consider both definitions and declarations.
Given that it makes little sense to write an entire program in a single file, though,
how does the rule above change when you use multiple units? In short, by referring
to another unit with a uses statement, the identifiers in the interface section of that
unit become visible to the new unit.
Reversing the perspective, if you declare an identifier (type, function, class, variable,
and so on) in the interface portion of a unit, it becomes visible to any other module
referring to that unit. If you declare an identifier in the implementation portion of a
unit, instead, it can only be used in that unit (and it is generally referred to as a local
identifier).

Using Units Like Namespaces


We have seen that the uses statement is the standard technique to access identifiers
declared in the scope of another unit. At that point you can access the definitions of
the unit. But it might happen that two units you refer to declare the same identifier;
that is, you might have two classes or two routines with the same name.
In this case you can simply use the unit name to prefix the name of the type or rou-
tine defined in the unit. For example, you can refer to the ComputeTotal procedure
defined in the given Calc unit as Calc.ComputeTotal. This isn't required often, as
you are strongly advised against using the same identifier for two different elements
of the same program, if you can avoid it.
However, if you look into the system or third party libraries, you’ll find functions
and classes that have the same name. A good example are the visual controls of dif-
ferent user interface frameworks. When you see a reference to TForm or TControl, it
could mean different classes depending on the actual units you refer to.
If the same identifier is exposed by two units in your uses statement, the one in the
last unit being used overrides the symbol, and will be the one that the compiler uses.
In other words, the symbols defined in the last unit in the list wins. If you simply
cannot avoid such a scenario, it is recommended to prefix the symbol with the unit
name, to avoid having you code depend on the order in which the units are listed.

The Program File


As we have seen, a Delphi application consists of two kinds of source code files: one
or more units and one, and only one, program file (saved in a DPR file). The units

Marco Cantù, Object Pascal Handbook


42 - 01: Coding in Pascal

can be considered secondary files, which are referenced by the main part of the
application, the program. In theory, this is true. In practice, the program file is usu-
ally an automatically generated file with a limited role. It simply needs to start up
the program, generally creating and running the main form, in case of a visual appli-
cation. The code of the program file can be edited manually, but it is also modified
automatically by using some of the Project Options of the IDE (like those related to
the application object and the forms).
The structure of the program file is usually much simpler than the structure of the
units. Here is the source code of a sample program file (with some optional standard
units omitted) that is automatically created by the IDE for you:
program Project1;

uses
FMX.Forms,
Unit1 in ‘Unit1.PAS’ {Form1};

begin
Application.Initialize;
Application.CreateForm (TForm1, Form1);
Application.Run;
end.
As you can see, there is simply a uses section and the main code of the application,
enclosed by the begin and end keywords. The program’s uses statement is particu-
larly important, because it is used to manage the compilation and linking of the
application.

note The list of units in the program file corresponds to the list of the units that are part of the project
in the IDE Project Manager. When you add a unit to a project in the IDE, the unit is automatically
added to the list in the program file source. The opposite happens if you remove it from the
project. In any case, if you edit the source code of the program file, the list of units in the Project
Manager is updated accordingly.

Compiler Directives
Another special element of the program structure (other than its actual code) are
compiler directives, as mentioned earlier. These are special instructions for the com-
piler, written with the format:
{$X+}

Marco Cantù, Object Pascal Handbook


01: Coding in Pascal - 43

Some compiler directives have a single character, as above, with a plus or minus
symbol indicating if the directive is activated or unactivated. Most of the directives
also have a longer and readable version, and use ON and OFF to mark if they are
active. Some directives have only the longer, descriptive format.
Compiler directives don't generate compiled code directly, but affect how the com-
piler generates code after the directive is encountered. In many cases, using a
compiler directive is an alternative to changing one of the compiler settings in the
IDE Project Options, although there are scenarios in which you want to apply a spe-
cific compiler setting only to a unit or to a fragment of code.
I'll cover specific compiler directives when relevant in the discussion of a language
feature they can affect. In this section I only want to mention a couple of directives
that relate to the program code flow: conditional defines and includes.

Conditional Defines
Conditional defines like $IFDEF let you indicate to the compiler to include a portion
of source code or ignore it. They can be based on defined symbols or on constant val-
ues. The defined symbols can be predefined by the system (like the platform
symbols), can be defined in a specific project option, or a can be introduced with
another compiler directive, $DEFINE:
{$DEFINE TEST}
...
{$IFDEF TEST}
// this is going to be compiled
{$ENDIF}

{$IFNDEF TEST}
// this is not going to be compiled
{$ENDIF}
You can also have two alternatives, using an $ELSE directive to separate them. A
more flexible alternative is the use of the $IF directive, closed by the $IFEND direc-
tive and based on expressions like comparison functions (which can refer to any
constant value in the code). So you can just define a constant and use an expression
against it. An example is shown below related to compiler versions, one of the com-
mon uses of system defines.

Marco Cantù, Object Pascal Handbook


44 - 01: Coding in Pascal

Compiler Versions
Each version of the Delphi compiler has a specific define you can use to check if you
are compiling against a specific version of the product. This might be required if you
are using a feature introduced later but want to make sure the code still compiles for
older versions.
If you need to have specific code for some of the recent versions of Delphi, you can
base your $IFDEF statements on the following defines:

Delphi 2007 VER180

Delphi XE VER220

Delphi XE2 VER230

Delphi XE4 VER250

Delphi XE5 VER260

Appmethod Spring 2014 VER260

Delphi XE6 VER270

Appmethod June 2014 VER270

Delphi XE7 VER280

Appmethod September 2014 VER280

Delphi XE8 VER290

Appmethod Spring 2015 VER290

The decimal digits of these version numbers indicate the actual compiler version (for
example 26 in Delphi XE5). The numeric sequence is not specific to Appmethod or
Delphi, but dates back to the first Turbo Pascal compiler published by Borland.
You can also use the internal versioning constant in $IF statements, with the advan-
tage of being able to use a comparison operator (>=) rather than a match for a
specific version. The versioning constant is called CompilerVersion and in Delphi
XE5 it's assigned to the floating-point value 26.0.
So for example:

Marco Cantù, Object Pascal Handbook


01: Coding in Pascal - 45

{$IF CompilerVersion >= 26)}


// code to compile in Delphi XE5 or later
{$IFEND}
Similarly, you can use system defines for the different platforms you can compile
for, in case you need some code to be platform-specific (generally an exception in
Object Pascal, not common practice):

Windows (both 32 and 64 bit) MSWINDOWS

Mac OS X MACOS

iOS IOS

Android ANDROID

Below is a code snippet with the tests based on the platforms define above, part of
the HelloPlatform project:
{$IFDEF IOS}
ShowMessage ('Running on iOS');
{$ENDIF}

{$IFDEF ANDROID}
ShowMessage ('Running on Android');
{$ENDIF}

Include Files
The other directive I want to cover here is the $INCLUDE directive, already mentioned
when discussing the uses statement. This directive lets you refer to and include a
fragment of source code in a given position of a source code file. At times this is used
to be able to include the same fragment in different units, in cases where the code
fragment defines compiler directives and other elements used directly by the com-
piler. When you use a unit, it is compiled only once. When you include a file, that
code is compiled within each of the units it is added to (which is why you should
generally avoid having any new identifier declared in an include file).
In other words, you should generally not add any language elements and definitions
in include files (unlike the C language), as this is what units are for. So how do you
use an include file? A good example is a set of compiler directives you want to enable
in most of your units, or some extra special defines.

Marco Cantù, Object Pascal Handbook

You might also like