13.2.8 The With statement

The with statement serves to access the elements of a record or object or class, without having to specify the element’s name each time. The syntax for a with statement is

_________________________________________________________________________________________________________
With statement

--            -|-             ---  -         -------------------
  with-statement  |-variable-reference-| do  statement
                       ,
____________________________________________

The variable reference must be a variable of a record, object or class type. In the with statement, any variable reference, or method reference is checked to see if it is a field or method of the record or object or class. If so, then that field is accessed, or that method is called. Given the declaration:

Type
  Passenger = Record
    Name : String[30];
    Flight : String[10];
  end;

Var
  TheCustomer : Passenger;

The following statements are completely equivalent:

TheCustomer.Name := 'Michael';
TheCustomer.Flight := 'PS901';

and

With TheCustomer do
  begin
  Name := 'Michael';
  Flight := 'PS901';
  end;

The statement

With A,B,C,D do Statement;

is equivalent to

With A do
 With B do
  With C do
   With D do Statement;

This also is a clear example of the fact that the variables are tried last to first, i. e., when the compiler encounters a variable reference, it will first check if it is a field or method of the last variable. If not, then it will check the last-but-one, and so on. The following example shows this;

Program testw;
Type AR = record
      X,Y : Longint;
     end;
     PAR = ˆAr;

Var S,T : Ar;
begin
  S.X := 1;S.Y := 1;
  T.X := 2;T.Y := 2;
  With S,T do
    WriteLn (X,' ',Y);
end.

The output of this program is

2 2

Showing thus that the X,Y in the WriteLn statement match the T record variable.

Remark
When using a With statement with a pointer, or a class, it is not permitted to change the pointer or the class in the With block. With the definitions of the previous example, the following illustrates what it is about:

Var p : PAR;

begin
  With Pˆ do
   begin
   // Do some operations
   P:=OtherP;
   X:=0.0;  // Wrong X will be used !!
   end;

The reason the pointer cannot be changed is that the address is stored by the compiler in a temporary register. Changing the pointer won’t change the temporary address. The same is true for classes.

Remark
There is a subtle difference between Delphi and Free Pascal when resolving identifiers in a With statement: Free Pascal will always search first in the scope of the expression used in the With statement, and only then will it search in the local scope. Delphi will first search in the local scope and then only in the with scope:

Type
  TField = Record
    Procedure Updating;
  end;

procedure Test;
var
  Updating: Boolean;
  F : TField;
begin
  Updating := Solo;
  // ..
  with F do
    Updating // TField.Updating in FPC, variable updating in Delphi
  // ..