RAD Studio (Common)
ContentsIndex
PreviousUpNext
Declarations and Statements

This topic describes the syntax of Delphi declarations and statements.  

Aside from the uses clause (and reserved words like implementation that demarcate parts of a unit), a program consists entirely of declarations and statements, which are organized into blocks

This topic covers the following items:

  • Declarations
  • Simple statements such as assignment
  • Structured statements such as conditional tests (e.g., if-then, and case), iteration (e.g., for, and while).
 

string;

The syntax and placement of a declaration depend on the kind of identifier you are defining. In general, declarations can occur only at the beginning of a block or at the beginning of the interface or implementation section of a unit (after the uses clause). Specific conventions for declaring variables, constants, types, functions, and so forth are explained in the documentation for those topics.

Hinting Directives

The 'hint' directives platform, deprecated, and library may be appended to any declaration. These directives will produce warnings at compile time. Hint directives can be applied to type declarations, variable declarations, class, interface and structure declarations, field declarations within classes or records, procedure, function and method declarations, and unit declarations. 

When a hint directive appears in a unit declaration, it means that the hint applies to everything in the unit. For example, the Windows 3.1 style OleAuto.pas unit on Windows is completely deprecated. Any reference to that unit or any symbol in that unit will produce a deprecation message. 

The platform hinting directive on a symbol or unit indicates that it may not exist or that the implementation may vary considerably on different platforms. The library hinting directive on a symbol or unit indicates that the code may not exist or the implementation may vary considerably on different library architectures. 

The platform and library directives do not specify which platform or library. If your goal is writing platform-independent code, you do not need to know which platform a symbol is specific to; it is sufficient that the symbol be marked as specific to some platform to let you know it may cause problems for your goal of portability. 

In the case of a procedure or function declaration, the hint directive should be separated from the rest of the declaration with a semicolon. Examples:

procedure SomeOldRoutine; stdcall deprecated;

var
   VersionNumber: Real library;
           
type 
   AppError = class(Exception)
     ...
end platform;

When source code is compiled in the {$HINTS ON} {$WARNINGS ON} state, each reference to an identifier declared with one of these directives generates an appropriate hint or warning. Use platform to mark items that are specific to a particular operating environment (such as Windows or .NET), deprecated to indicate that an item is obsolete or supported only for backward compatibility, and library to flag dependencies on a particular library or component framework. 

The RAD Studio compiler also recognizes the hinting directive experimental. You can use this directive to designate units which are in an unstable, development state. The compiler will emit a warning when it builds an application that uses the unit.

The names of variables, constants, types, fields, properties, procedures, functions, programs, units, libraries, and packages are called identifiers. (Numeric constants like 26057 are not identifiers.) Identifiers must be declared before you can use them; the only exceptions are a few predefined types, routines, and constants that the compiler understands automatically, the variable Result when it occurs inside a function block, and the variable Self when it occurs inside a method implementation. 

A declaration defines an identifier and, where appropriate, allocates memory for it. For example,

var Size: Extended;

declares a variable called Size that holds an Extended (real) value, while

function DoThis(X, Y: string): Integer;

declares a function called DoThis that takes two strings as arguments and returns an integer. Each declaration ends with a semicolon. When you declare several variables, constants, types, or labels at the same time, you need only write the appropriate reserved word once:

var
   Size: Extended;
   Quantity: Integer;

Statements define algorithmic actions within a program. Simple statements like assignments and procedure calls can combine to form loops, conditional statements, and other structured statements. 

Multiple statements within a block, and in the initialization or finalization section of a unit, are separated by semicolons.

A simple statement doesn't contain any other statements. Simple statements include assignments, calls to procedures and functions, and goto jumps.

Assignment Statements

An assignment statement has the form 

variable := expression 

where variable is any variable reference, including a variable, variable typecast, dereferenced pointer, or component of a structured variable. The expression is any assignment-compatible expression (within a function block, variable can be replaced with the name of the function being defined. See Procedures and functions). The := symbol is sometimes called the assignment operator. 

An assignment statement replaces the current value of variable with the value of expression. For example,

I := 3;

assigns the value 3 to the variable I. The variable reference on the left side of the assignment can appear in the expression on the right. For example,

I := I + 1;

increments the value of I. Other assignment statements include

X := Y + Z;
Done := (I >= 1) and (I < 100);
Hue1 := [Blue, Succ(C)];
I := Sqr(J) - I  * K;
Shortint(MyChar) := 122;
TByteRec(W).Hi := 0;
MyString[I] := 'A';
SomeArray[I + 1] := P^;
TMyObject.SomeProperty := True;

 

Procedure and Function Calls

A procedure call consists of the name of a procedure (with or without qualifiers), followed by a parameter list (if required). Examples include

PrintHeading;
Transpose(A, N, M);
Find(Smith, William);
Writeln('Hello world!');
DoSomething();
Unit1.SomeProcedure;
TMyObject.SomeMethod(X,Y);

With extended syntax enabled ({$X+}), function calls, like calls to procedures, can be treated as statements in their own right:

MyFunction(X);

When you use a function call in this way, its return value is discarded. 

For more information about procedures and functions, see Procedures and functions.

Goto Statements

A goto statement, which has the form

goto label

transfers program execution to the statement marked by the specified label. To mark a statement, you must first declare the label. Then precede the statement you want to mark with the label and a colon: 

label: statement 

Declare labels like this: 

labellabel; 

You can declare several labels at once: 

labellabel1, ..., labeln; 

A label can be any valid identifier or any numeral between 0 and 9999. 

The label declaration, marked statement, and goto statement must belong to the same block. (See Blocks and Scope, below.) Hence it is not possible to jump into or out of a procedure or function. Do not mark more than one statement in a block with the same label. 

For example,

label StartHere;
    ...
StartHere: Beep;
goto StartHere;

creates an infinite loop that calls the Beep procedure repeatedly. 

Additionally, it is not possible to jump into or out of a try-finally or try-except statement. 

The goto statement is generally discouraged in structured programming. It is, however, sometimes used as a way of exiting from nested loops, as in the following example.

procedure FindFirstAnswer;
  var X, Y, Z, Count: Integer;
label FoundAnAnswer;
begin
  Count := SomeConstant;
  for X := 1 to Count do
    for Y := 1 to Count do
      for Z := 1 to Count do
        if ... { some condition holds on X, Y, and Z } then
          goto FoundAnAnswer;

        ... { Code to execute if no answer is found }
        Exit;

FoundAnAnswer:
        ... { Code to execute when an answer is found }
end;

Notice that we are using goto to jump out of a nested loop. Never jump into a loop or other structured statement, since this can have unpredictable effects.

Structured statements are built from other statements. Use a structured statement when you want to execute other statements sequentially, conditionally, or repeatedly.

  • A compound or with statement simply executes a sequence of constituent statements.
  • A conditional statement that is an if or case statement executes at most one of its constituents, depending on specified criteria.
  • Loop statements including repeat, while, and for loops execute a sequence of constituent statements repeatedly.
  • A special group of statements including raise, try...except, and try...finally constructions create and handle exceptions. For information about exception generation and handling, see Exceptions.
 

Compound Statements

A compound statement is a sequence of other (simple or structured) statements to be executed in the order in which they are written. The compound statement is bracketed by the reserved words begin and end, and its constituent statements are separated by semicolons. For example:

begin
   Z := X;
   X := Y;
   X := Y;
          end;

The last semicolon before end is optional. So we could have written this as

begin
   Z := X;
   X := Y;
   Y := Z
end;

Compound statements are essential in contexts where Delphi syntax requires a single statement. In addition to program, function, and procedure blocks, they occur within other structured statements, such as conditionals or loops. For example:

begin
   I := SomeConstant;
   while I > 0 do
    begin
       ...
       I := I - 1;
    end;
end;

You can write a compound statement that contains only a single constituent statement; like parentheses in a complex term, begin and end sometimes serve to disambiguate and to improve readability. You can also use an empty compound statement to create a block that does nothing:

begin
end;

 

With Statements

A with statement is a shorthand for referencing the fields of a record or the fields, properties, and methods of an object. The syntax of a with statement is

  1. withobjdostatement, or
  2. withobj1, ..., objndostatement
where obj is an expression yielding a reference to a record, object instance, class instance, interface or class type (metaclass) instance, and statement is any simple or structured statement. Within the statement, you can refer to fields, properties, and methods of obj using their identifiers alone, that is, without qualifiers. 

For example, given the declarations

type 
  TDate = record
    Day: Integer;
    Month: Integer;
    Year: Integer;
  end;

var
  OrderDate: TDate;

you could write the following with statement.

with OrderDate do
 if Month = 12 then
   begin
     Month := 1;
     Year := Year + 1;
   end
 else
   Month := Month + 1;

you could write the following with statement.

if OrderDate.Month = 12 then
  begin
   OrderDate.Month := 1;
   OrderDate.Year := OrderDate.Year + 1;
  end
else
  OrderDate.Month := OrderDate.Month + 1;

If the interpretation of obj involves indexing arrays or dereferencing pointers, these actions are performed once, before statement is executed. This makes with statements efficient as well as concise. It also means that assignments to a variable within statement cannot affect the interpretation of obj during the current execution of the with statement. 

Each variable reference or method name in a with statement is interpreted, if possible, as a member of the specified object or record. If there is another variable or method of the same name that you want to access from the with statement, you need to prepend it with a qualifier, as in the following example.

with OrderDate do 
  begin
    Year := Unit1.Year;
       ...
  end;

When multiple objects or records appear after with, the entire statement is treated like a series of nested with statements. Thus 

withobj1, obj2, ..., objndostatement 

is equivalent to

with obj1 do
  with obj2 do
    ...
    with objn do
      // statement

In this case, each variable reference or method name in statement is interpreted, if possible, as a member of objn; otherwise it is interpreted, if possible, as a member of objn1; and so forth. The same rule applies to interpreting the objs themselves, so that, for instance, if objn is a member of both obj1 and obj2, it is interpreted as obj2.objn.

If Statements

There are two forms of if statement: if...then and the if...then...else. The syntax of an if...then statement is 

ifexpressionthenstatement 

where expression returns a Boolean value. If expression is True, then statement is executed; otherwise it is not. For example,

if J <> 0 then Result := I / J;

The syntax of an if...then...else statement is 

ifexpressionthenstatement1elsestatement2 

where expression returns a Boolean value. If expression is True, then statement1 is executed; otherwise statement2 is executed. For example,

if J = 0 then 
   Exit
else
   Result := I / J;

The then and else clauses contain one statement each, but it can be a structured statement. For example,

if J <> o then
  begin
    Result := I / J;
    Count := Count + 1;
  end
else if Count = Last then
        Done := True
else
  Exit;

Notice that there is never a semicolon between the then clause and the word else. You can place a semicolon after an entire if statement to separate it from the next statement in its block, but the then and else clauses require nothing more than a space or carriage return between them. Placing a semicolon immediately before else (in an if statement) is a common programming error. 

A special difficulty arises in connection with nested if statements. The problem arises because some if statements have else clauses while others do not, but the syntax for the two kinds of statement is otherwise the same. In a series of nested conditionals where there are fewer else clauses than if statements, it may not seem clear which else clauses are bound to which ifs. Consider a statement of the form 

ifexpression1thenifexpression2thenstatement1elsestatement2

There would appear to be two ways to parse this: 

ifexpression1 then [ ifexpression2thenstatement1elsestatement2 ]; 

ifexpression1then [ ifexpression2thenstatement1 ] elsestatement2

The compiler always parses in the first way. That is, in real code, the statement

if ... { expression1} then
  if ... {expression2} then
    ... {statement1}
  else
    ... {statement2}

is equivalent to

if ... {expression1} then
  begin
    if ... {expression2} then
      ... {statement1}
    else
      ... {statement2}
end;

The rule is that nested conditionals are parsed starting from the innermost conditional, with each else bound to the nearest available if on its left. To force the compiler to read our example in the second way, you would have to write it explicitly as

if ... {expression1} then
  begin
   if ... {expression2} then
     ... {statement1}
   end
end
else
   ... {statement2};

 

Case Statements

The case statement may provide a readable alternative to deeply nested if conditionals. A case statement has the form

case selectorExpression of
   caseList1: statement1;
     ...
   caseListn: statementn;
end

where selectorExpression is any expression of an ordinal type smaller than 32 bits (string types and ordinals larger than 32 bits are invalid) and each caseList is one of the following:

  • A numeral, declared constant, or other expression that the compiler can evaluate without executing your program. It must be of an ordinal type compatible with selectorExpression. Thus 7, True, 4 + 5 * 3, 'A', and Integer('A') can all be used as caseLists, but variables and most function calls cannot. (A few built-in functions like Hi and Lo can occur in a caseList. See Constant expressions.)
  • A subrange having the form First..Last, where First and Last both satisfy the criterion above and First is less than or equal to Last.
  • A list having the form item1, ..., itemn, where each item satisfies one of the criteria above.
Each value represented by a caseList must be unique in the case statement; subranges and lists cannot overlap. A case statement can have a final else clause:

case selectorExpression of
   caseList1: statement1;
      ...
   caselistn: statementn;
   else
      statements;
end

where statements is a semicolon-delimited sequence of statements. When a case statement is executed, at most one of statement1 ... statementn is executed. Whichever caseList has a value equal to that of selectorExpression determines the statement to be used. If none of the caseLists has the same value as selectorExpression, then the statements in the else clause (if there is one) are executed. 

The case statement

case I of
   1..5: Caption := 'Low';
   6..9: Caption := 'High';
   0, 10..99: Caption := 'Out of range';
   else
     Caption := '';
end

is equivalent to the nested conditional

if I in [1..5] then
   Caption := 'Low';
else if I in [6..10] then
        Caption := 'High';
     else if (I = 0) or (I in [10..99]) then
            Caption := 'Out of range'
          else
            Caption := '';

Other examples of case statements

case MyColor of
   Red: X := 1;
   Green: X := 2;
   Blue: X = 3;
   Yellow, Orange, Black: X := 0;
end;

case Selection of
   Done: Form1.Close;
   Compute: calculateTotal(UnitCost, Quantity);
   else
      Beep;
end;

 

Control Loops

Loops allow you to execute a sequence of statements repeatedly, using a control condition or variable to determine when the execution stops. Delphi has three kinds of control loop: repeat statements, while statements, and for statements. 

You can use the standard Break and Continue procedures to control the flow of a repeat, while, or for statement. Break terminates the statement in which it occurs, while Continue begins executing the next iteration of the sequence.

Repeat Statements

The syntax of a repeat statement is 

repeatstatement1; ...; statementn;untilexpression 

where expression returns a Boolean value. (The last semicolon before until is optional.) The repeat statement executes its sequence of constituent statements continually, testing expression after each iteration. When expression returns True, the repeat statement terminates. The sequence is always executed at least once because expression is not evaluated until after the first iteration. 

Examples of repeat statements include

repeat
  K := I mod J;
  I := J;
  J := K;
until J = 0;

repeat
  Write('Enter a value (0..9): ');
  Readln(I);
until (I >= 0) and (I <= 9);

 

While Statements

A while statement is similar to a repeat statement, except that the control condition is evaluated before the first execution of the statement sequence. Hence, if the condition is false, the statement sequence is never executed. 

The syntax of a while statement is 

whileexpressiondostatement 

where expression returns a Boolean value and statement can be a compound statement. The while statement executes its constituent statement repeatedly, testing expression before each iteration. As long as expression returns True, execution continues. 

Examples of while statements include

while Data[I] <> X do I := I + 1;

  while I > 0 do
   begin
      if Odd(I) then Z := Z * X;
         I := I div 2;
         X := Sqr(X);
   end;

  while not Eof(InputFile) do
   begin
      Readln(InputFile, Line);
      Process(Line);
   end;

 

For Statements

A for statement, unlike a repeat or while statement, requires you to specify explicitly the number of iterations you want the loop to go through. The syntax of a for statement is 

for counter := initialValue to finalValue do statement 

or 

for counter := initialValue downto finalValue do statement 

where

  • counter is a local variable (declared in the block containing the for statement) of ordinal type, without any qualifiers.
  • initialValue and finalValue are expressions that are assignment-compatible with counter.
  • statement is a simple or structured statement that does not change the value of counter.
The for statement assigns the value of initialValue to counter, then executes statement repeatedly, incrementing or decrementing counter after each iteration. (The for...to syntax increments counter, while the for...downto syntax decrements it.) When counter returns the same value as finalValue, statement is executed once more and the for statement terminates. In other words, statement is executed once for every value in the range from initialValue to finalValue. If initialValue is equal to finalValue, statement is executed exactly once. If initialValue is greater than finalValue in a for...to statement, or less than finalValue in a for...downto statement, then statement is never executed. After the for statement terminates (provided this was not forced by a Break or an Exit procedure), the value of counter is undefined.
Warning: The iteration variable counter cannot be modified within the loop. This includes assignment, and passing the variable to a var
parameter of a procedure. Doing so results in a compile-time warning. For purposes of controlling execution of the loop, the expressions initialValue and finalValue are evaluated only once, before the loop begins. Hence the for...to statement is almost, but not quite, equivalent to this while construction:

begin
   counter := initialValue;
   while counter <= finalValue do
    begin
      ... {statement};
      counter := Succ(counter);
    end;
end

The difference between this construction and the for...to statement is that the while loop reevaluates finalValue before each iteration. This can result in noticeably slower performance if finalValue is a complex expression, and it also means that changes to the value of finalValue within statement can affect execution of the loop. 

Examples of for statements:

for I := 2 to 63 do
  if Data[I] > Max then
     Max := Data[I];

for I := ListBox1.Items.Count - 1 downto 0 do
    ListBox1.Items[I] := UpperCase(ListBox1.Items[I]);

for I := 1 to 10 do 
    for J := 1 to 10 do 
       begin
           X := 0;
           for K := 1 to 10 do 
               X := X + Mat1[I,K] * Mat2[K,J];
           Mat[I,J] := X;
       end;

for C := Red to Blue do Check(C);

 

Iteration Over Containers Using For statements

Both Delphi for .NET and for Win32 support for-element-in-collection style iteration over containers. The following container iteration patterns are recognized by the compiler:

  • for Element in ArrayExpr do Stmt;
  • for Element in StringExpr do Stmt;
  • for Element in SetExpr do Stmt;
  • for Element in CollectionExpr do Stmt;
  • for Element in Record do Stmt;
The type of the iteration variable Element must match the type held in the container. With each iteration of the loop, the iteration variable holds the current collection member. As with regular for-loops, the iteration variable must be declared within the same block as the for statement.
Warning: The iteration variable cannot be modified within the loop. This includes assignment, and passing the variable to a var
parameter of a procedure. Doing so results in a compile-time warning. Array expressions can be single or multidimensional, fixed length, or dynamic arrays. The array is traversed in increasing order, starting at the lowest array bound and ending at the array size minus one. The following code shows an example of traversing single, multi-dimensional, and dynamic arrays:

type
  TIntArray        = array[0..9] of Integer;
  TGenericIntArray = array of Integer;

var
  IArray1: array[0..9] of Integer   = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  IArray2: array[1..10] of Integer  = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  IArray3: array[1..2] of TIntArray = ((11, 12, 13, 14, 15, 16, 17, 18, 19, 20),
                                       (21, 22, 23, 24, 25, 26, 27, 28, 29, 30));
  MultiDimTemp: TIntArray;
  IDynArray:    TGenericIntArray;

  I: Integer;

begin
  
  for I in IArray1 do 
     begin 
         // Do something with I...
     end;

  // Indexing begins at lower array bound of 1.
  for I in IArray2 do
     begin
         // Do something with I...
     end;

  // Iterating a multi-dimensional array
  for MultiDimTemp in IArray3 do   // Indexing from 1..2
    for I in MultiDimTemp do       // Indexing from 0..9
      begin
          // Do something with I...
      end;

  // Iterating over a dynamic array
  IDynArray := IArray1;
  for I in IDynArray do
     begin
        // Do something with I...
     end;

The following example demonstrates iteration over string expressions:

var
  C: Char;
  S1, S2: String;
  Counter: Integer;

  OS1, OS2: ShortString;
  AC: AnsiChar;
  
begin

  S1 := 'Now is the time for all good men to come to the aid of their country.';
  S2 := '';

  for C in S1 do
    S2 := S2 + C;

  if S1 = S2 then
    WriteLn('SUCCESS #1');
  else
    WriteLn('FAIL #1');

  OS1 := 'When in the course of human events it becomes necessary to dissolve...';
  OS2 := '';

  for AC in OS1 do
    OS2 := OS2 + AC;

  if OS1 = OS2 then
    WriteLn('SUCCESS #2');
  else
    WriteLn('FAIL #2');

end.

The following example demonstrates iteration over set expressions:

type

  TMyThing = (one, two, three);
  TMySet   = set of TMyThing;
  TCharSet = set of Char;

var
  MySet:   TMySet;
  MyThing: TMyThing;

  CharSet: TCharSet;
  {$IF DEFINED(CLR)}
  C: AnsiChar;
  {$ELSE}
  C: Char;
  {$IFEND}

begin

  MySet := [one, two, three];
  for MyThing in MySet do
   begin
    // Do something with MyThing...
   end;


  CharSet := [#0..#255];
  for C in CharSet do
    begin
      // Do something with C...
    end;

end.

To use the for-in loop construct on a class or interface, the class or interface must implement a prescribed collection pattern. A type that implements the collection pattern must have the following attributes:

  • The class or interface must contain a public instance method called GetEnumerator(). The GetEnumerator() method must return a class, interface, or record type.
  • The class, interface, or record returned by GetEnumerator() must contain a public instance method called MoveNext(). The MoveNext() method must return a Boolean.
  • The class, interface, or record returned by GetEnumerator() must contain a public instance, read-only property called Current. The type of the Current property must be the type contained in the collection.
If the enumerator type returned by GetEnumerator() implements the IDisposable interface, the compiler will call the Dispose method of the type when the loop terminates. 

The following code demonstrates iterating over an enumerable container in Delphi.

type
  TMyIntArray = array of Integer;

  TMyEnumerator = class
    Values: TMyIntArray;
    Index:  Integer;
  public
    constructor Create;
    function GetCurrent: Integer;
    function MoveNext:   Boolean;
    property Current:    Integer read GetCurrent;
  end;

  TMyContainer  = class
  public
   function GetEnumerator: TMyEnumerator;
  end;

constructor TMyEnumerator.Create;
begin
  inherited Create;
  Values := TMyIntArray.Create(100, 200, 300);
  Index := -1;
end;

function TMyEnumerator.MoveNext: Boolean;
begin
  if Index < High(Values) then
    begin
      Inc(Index);
      Result := True;
    end
  else
    Result := False;
end;

function TMyEnumerator.GetCurrent: Integer;
begin
  Result := Values[Index];
end;

function TMyContainer.GetEnumerator: TMyEnumerator;
begin
  Result := TMyEnumerator.Create;
end;

var
  MyContainer: TMyContainer;
  I: Integer;

  Counter: Integer;

begin
  MyContainer := TMyContainer.Create;

  Counter := 0;
  for I in MyContainer do
    Inc(Counter, I);

  WriteLn('Counter = ', Counter);
end.

The following classes and their descendents support the for-in syntax:

  • TList
  • TCollection
  • TStrings
  • TInterfaceList
  • TComponent
  • TMenuItem
  • TCustomActionList
  • TFields
  • TListItems
  • TTreeNodes
  • TToolBar

Declarations and statements are organized into blocks, which define local namespaces (or scopes) for labels and identifiers. Blocks allow a single identifier, such as a variable name, to have different meanings in different parts of a program. Each block is part of the declaration of a program, function, or procedure; each program, function, or procedure declaration has one block.

Blocks

A block consists of a series of declarations followed by a compound statement. All declarations must occur together at the beginning of the block. So the form of a block is

{declarations}
begin
  {statements}
end

The declarations section can include, in any order, declarations for variables, constants (including resource strings), types, procedures, functions, and labels. In a program block, the declarations section can also include one or more exports clauses (see Libraries and packages). 

For example, in a function declaration like

function UpperCase(const S: string): string;
var
  Ch: Char;
  L: Integer;
  Source, Dest: PChar;
begin
   ...
end;

the first line of the declaration is the function heading and all of the succeeding lines make up the block. Ch, L, Source, and Dest are local variables; their declarations apply only to the UpperCase function block and override, in this block only, any declarations of the same identifiers that may occur in the program block or in the interface or implementation section of a unit.

Scope

An identifier, such as a variable or function name, can be used only within the scope of its declaration. The location of a declaration determines its scope. An identifier declared within the declaration of a program, function, or procedure has a scope limited to the block in which it is declared. An identifier declared in the interface section of a unit has a scope that includes any other units or programs that use the unit where the declaration occurs. Identifiers with narrower scope, especially identifiers declared in functions and procedures, are sometimes called local, while identifiers with wider scope are called global. 

The rules that determine identifier scope are summarized below.

If the identifier is declared in ...  
its scope extends ... 
the declaration section of a program, function, or procedure  
from the point where it is declared to the end of the current block, including all blocks enclosed within that scope.  
the interface section of a unit  
from the point where it is declared to the end of the unit, and to any other unit or program that uses that unit. (See Programs and Units.)  
the implementation section of a unit, but not within the block of any function or procedure  
from the point where it is declared to the end of the unit. The identifier is available to any function or procedure in the unit, including the initialization and finalization sections, if present.  
the definition of a record type (that is, the identifier is the name of a field in the record)  
from the point of its declaration to the end of the record-type definition. (See Records.)  
the definition of a class (that is, the identifier is the name of a data field property or method in the class)  
from the point of its declaration to the end of the class-type definition, and also includes descendants of the class and the blocks of all methods in the class and its descendants. (See Classes and Objects.)  

 

Naming Conflicts

When one block encloses another, the former is called the outer block and the latter the inner block. If an identifier declared in an outer block is redeclared in an inner block, the inner declaration takes precedence over the outer one and determines the meaning of the identifier for the duration of the inner block. For example, if you declare a variable called MaxValue in the interface section of a unit, and then declare another variable with the same name in a function declaration within that unit, any unqualified occurrences of MaxValue in the function block are governed by the second, local declaration. Similarly, a function declared within another function creates a new, inner scope in which identifiers used by the outer function can be redeclared locally. 

The use of multiple units further complicates the definition of scope. Each unit listed in a uses clause imposes a new scope that encloses the remaining units used and the program or unit containing the uses clause. The first unit in a uses clause represents the outermost scope and each succeeding unit represents a new scope inside the previous one. If two or more units declare the same identifier in their interface sections, an unqualified reference to the identifier selects the declaration in the innermost scope, that is, in the unit where the reference itself occurs, or, if that unit doesn't declare the identifier, in the last unit in the uses clause that does declare the identifier. 

The System and SysInit units are used automatically by every program or unit. The declarations in System, along with the predefined types, routines, and constants that the compiler understands automatically, always have the outermost scope. 

You can override these rules of scope and bypass an inner declaration by using a qualified identifier (see Qualified Identifiers) or a with statement (see With Statements, above).

Copyright(C) 2008 CodeGear(TM). All Rights Reserved.
What do you think about this topic? Send feedback!