SCOPE / VISIBILITY
In this column, we have a detailed look at the SCOPE and VISIBILTY of identifiers.
The scope of an identifier is that part of the program in which the identifier can be used to access the corresponding variable, constant, object, type, procedure or function.
The visibility of an identifier usually is the same as its scope, but sometimes the visibility is less than the scope.
Scope: from narrow to wide
- Local identifiers are declared in a block above the begin..end code block of a procedure or function. Local identifiers only can be used inside that procedure or function.
procedure Test(P1, P2: integer);
LANG = 'ENG';
TDigits = set of '0'..'9';
// some code...
In the example above, also the parameters P1 and P2 are local variables.
- Identifiers that are declared in the implementation section of a unit (before any procedure or function) have a scope limited to the implementation section of that unit. Example:
procedure TForm1.Button1Click(Sender: TObject);
Here, the variable FullName is accessible from any procedure and function in the implementation section. But FullName is not accessible from anywhere in the interface section, nor from any other unit.
- Identifiers declared in the interface section of a unit can be accessed from anywhere in that unit, and from any other unit that references the first unit in a "uses" clause.
- Global identifiers have the widest scope, they can be accessed from each unit of your project. You define global identifiers in a unit such as this:
PROJECTLANG = 'ENG';
Now, to make the identifiers of the unit "globals" in another unit, say in "unit1", include "globals" in the USES list of unit1.
- You can even make identifiers global to the entire project. This might be useful for global settings, such as language settings of the program. Just add the "globals" unit to the USES list of your project file (DPR), such as:
uses [unit1, unit2, ...,] globals;
- As a general rule, you should limit the scope of variables as much as possible.
- Comment, comment, comment. If you do something out of the ordinary, add some comments to your code, such as:
ShowMessage(ProgName); // ProgName is declared in GLOBALS.PAS
- Scope and visibility usually are the same, but there are circumstances under which an identifier becomes temporarily hidden by the appearance of an identifier with the same name. You should try to avoid this as much as possible. For example, don't declare a variable named "Width" in a unit that declares a form, because a form has a property that is also named "Width".
Visibility cannot exceed scope, but scope can exceed visibility.
- Attention: be careful when giving names to variables and stuff (see also above, point 2). Avoid identifiers that are commonly used for properties or methods of Delphi's VCL components, such as Click, Color, Height, Show, Width,...
Tip: if you are not sure about an identifier, use a prefix such as "the" or "my", for example: myColor, theHeight,...
- The "inline" variable declaration syntax allows you to declare a variable directly in a code block, instead of "above" that code block (since Delphi version 10.3). An inline variable is visible from the position of its declaration and up to the end of the code block. Example:
// Some code...
// Here, J and K are not visible yet
// Some more code...
var J, K: Integer;
// From here on, J and K are visible
J := 22;
The inline declaration and initialization of a variable can be done in a single statement. Example:
var J: Integer := 22;
var K: Integer := 22 + J;