Chapter 7. Operators

This chapter describes the symbolic operators, their precedence and semantics. Chapter 5, describes the named operators in depth, but not the symbolic operators, because it’s hard to alphabetize symbols. This chapter describes the symbolic operators in depth.

Delphi defines the following operators. Each line lists the operators with the same precedence; operator precedence is highest at the start of the list and lowest at the bottom:

@ not ^ + - (unary operators)
* / div mod and shl shr as
+ - or xor
> < >= <= <> = in is

A Variant can be a string, number, Boolean, or other value. If an expression mixes Variant and non-Variant operands, Delphi converts all operands to Variant. If the Variant types do not match, Delphi casts one or both operands as needed for the operation, and produces a Variant result. See the Variant type in Chapter 5 for more information about Variant type casts.

Unary Operators

@ operator

Returns the address of its operand. The address of a variable or ordinary subroutine is a Pointer, or if the $T or $TypedAddress compiler directive is used, a typed pointer (e.g., PInteger).

The address of a method has two parts: a code pointer and a data pointer, so you can assign a method address only to a variable of the appropriate type, and not to a generic Pointer variable. If you take the address of a method using a class reference instead of an object reference, the @ operator returns just the code pointer. For example:

Ptr := @TObject.Free;

When assigning the address of a subroutine to a procedural-type variable, if the subroutine’s signature matches the variable’s type, you do not need the @ operator. Delphi can tell from the assignment that you are assigning the subroutine’s address. If the types do not match, use the @ operator to take the subroutine’s address. For example, to assign an error procedure to Delphi’s ErrorProc variable, which is an untyped Pointer, you must use the @ operator:

function GetHeight: Integer;
begin
  Result := 42;
end;

procedure HandleError(Code: Integer; Addr: Pointer);
begin
  ...
end;

type
  TIntFunction = function: Integer;
var
  F: TIntFunction;
  I: Integer;
begin
  // Do not need @ operator. Assign GetHeight address to F.
  F := GetHeight;
  // Call GetHeight.
  I := F;

  // Need the @ operator because the type of ErrorProc is Pointer.  
  ErrorProc := @HandleError;

  // Call GetHeight via F, and compare integer results
  if F = GetHeight then
    ShowMessage('Heights are equal'),
  // Compare pointers to learn whether F points to GetHeight.
  if @F = @GetHeight then
    ShowMessage('Function pointers are equal'),

You can also use the @ operator on the left-hand side of an assignment to assign a procedural pointer that does not have the correct type. For example, the value returned from the Windows API function GetProcAddress is a procedure address, but it has the generic Pointer type. A type cast is usually the best way to solve this problem, but some people prefer to use the @ operator on the left-hand side of an assignment, for example:

type
  TIntFunction = function: Integer;
var
  F: TIntFunction;
begin
  // The following two statements do the same thing:
  @F := GetProcAddress(DllHandle, 'GetHeight'),
  F := TIntFunction(GetProcAddress(DllHandle, 'GetHeight'));

To take the address of a procedural-type variable, repeat the @ operator, for example, @@ Variable :

var
  F: TIntPointer;
  P: Pointer;
begin
  F := GetHeight;       // F points to GetHeight.
  P := @@F;             // Store address of the variable F in P.
Not operator

Logical negation. See the not keyword in Chapter 5 for details.

^ operator

Pointer dereference. This postfix operator follows a pointer-type expression and returns the value it points to. The type of the result is the base type of the pointer.

When accessing a record member or array element via a pointer, Delphi automatically supplies one level of indirection if needed. For example:

type
  TRecord = record
    Member: PInteger;
  end;
  PRecord = ^TRecord;
var
  P: PRecord;
  I: Integer;
begin
  New(P);
  P.Member := @I;     // Implicit P^.Member
  P.Member^ := 10;    // Need explicit ^ without record member reference
+ operator

Sign identity. The + operator can be used before any numeric expression. It has no effect, that is, +7 = 7.

- operator

Arithmetic negation. The - operator can be used before any numeric expression to change the sign of the expression, e.g., -(X + Y). Note that Delphi parses a negative constant as the - operator applied to a positive constant. That means you cannot write the most negative integer in decimal. You can use Low(Integer) instead.

Multiplicative Operators

* operator

The multiplication operator is also the set intersection operator. When the operands are sets of the same type, the result is a set that contains all members that are in both operand sets. For example:

var
  A, B, C: set of 0..7;
begin
  A := [0, 1, 2, 3];
  B := [2, 3, 4, 5, 6];
  C := A * B;           // C := [2,3]
  A := [1, 0];
  C := A * B;           // C := []
/ operator

Floating-point division. Dividing two integers converts the operands to floating point. Division by zero raises runtime error 7.

Div operator

Integer division. See Chapter 5 for details.

Mod operator

Modulus (remainder). See Chapter 5 for details.

And operator

Logical or bitwise conjunction. See Chapter 5 for details.

Shl operator

Left shift. See Chapter 5 for details.

Shr operator

Right shift. See Chapter 5 for details.

As operator

Type check and cast of object and interface references. See Chapter 5 for details.

Additive Operators

+ operator

Addition, string concatenation, set union, and PChar pointer offset. If both operands are strings, the result is the string concatenation of the two strings. If the operands are sets with the same type, the result is a set that contains all the elements in both operand sets.

If one operand has type PChar or PWideChar and the other is an integer, the result is a pointer whose value is offset by the integer in character units (not bytes). The integer offset can be positive or negative, but the resulting pointer must lie within the same character array as the PChar or PWideChar operand. For example:

var
  A, B, C: set of 0..7;
  Text: array[0..5] of Char;
  P, Q: PChar;
begin
  A := [0, 1, 2];
  B := [5, 7, 4];
  C := A + B;          // C := [0, 1, 2, 4, 5, 7];

  Text := 'Hello';
  P := Text;
  Q := P + 3;
  WriteLn(Q);          // Writes 'lo'
  WriteLn('Hi' + Q);   // Writes 'Hilo'
- operator

Subtraction, set difference, PChar pointer offset, and PChar difference. If the operands are sets with the same type, the result is a set that contains the elements that are in the left-hand operand set but not in the right-hand operand.

If one operand has type PChar or PWideChar and the other is an integer, the result is a pointer whose value is offset by the integer, in character units (not bytes). The integer offset can be positive or negative, but the resulting pointer must lie within the same character array as the PChar or PWideChar operand.

If both operands are of type PChar or PWideChar and both pointers point into the same character array, the difference is the number of characters between the two pointers. The difference is positive if the left-hand operand points to a later character than the right-hand operand, and the difference is negative if the left-hand operand points to a character that appears earlier in the character array:

var
  A, B, C: set of 0..7;
  Text: array[0..5] of Char;
  P, Q: PChar;
begin
  A := [0, 1, 2, 4, 5, 6];
  B := [5, 7, 4];
  C := A - B;          // C := [0, 1, 2, 6];
  C := B - A;          // C := [7];

  Text := 'Hello';
  P := Text;
  Q := P + 3;
  WriteLn(Q);          // Writes 'lo'
  P := Q - 2;
  WriteLn(P);          // Writes 'ello'
  WriteLn(Q - P);      // Writes 2
Or operator

Logical or bitwise disjunction. See Chapter 5 for details.

Xor operator

Logical or bitwise exclusive or. See Chapter 5 for details.

Comparison Operators

The comparison operators let you compare numbers, strings, sets, and pointers.

= operator

Equality. Compare numbers, strings, pointers, and sets for exact equality.

Note that comparing floating-point numbers for exact equality rarely works the way you think it should. You should use a fuzzy comparison that accounts for floating-point imprecision. See D. E. Knuth’s Seminumerical Algorithms (third edition, Addison Wesley Longman, 1998), section 4.2.2, for an excellent discussion of this problem and suggested solutions.

<> operator

Inequality. Compare numbers, strings, or character pointers, and sets. Returns the logical negation of the = operator.

> operator

Greater than; compares numbers, strings, or character pointers. When you compare PChar or PWideChar values, you are comparing pointers. The operator returns True if the left-hand operand points to a later position than the right-hand operand. Both operands must point to locations in the same character array. Strings are compared by comparing their characters’ ordinal values. (The SysUtils unit contains functions that compare strings taking into account the Windows locale. Most applications should use these functions instead of a simple string comparison. See Appendix B, for details.) For example:

var
  Text: array[0..5] of Char;
  P, Q: PChar;
begin
  Text := 'Hello';
  P := Text;
  Q := P + 3;
  WriteLn(Q > P);    // True because Q points to a later element than P
  if Text > 'Howdy' then
    // string comparison is False
< operator

Less than; compares numbers or strings, or character pointers. When you compare PChar or PWideChar values, you are comparing pointers. The operator returns True if the left-hand operand points to an earlier position than the right-hand operand. Both operands must point to locations in the same character array. Strings are compared by comparing their characters’ ordinal values. (The SysUtils unit contains functions that compare strings taking into account the Windows locale. Most applications should use these functions instead of a simple string comparison. See Appendix B for details.) For example:

var
  Text: array[0..5] of Char;
  P, Q: PChar;
begin
  Text := 'Hello';
  P := Text;
  Q := P + 3;
  WriteLn(Q < P);    // False because Q points to a later element than P
  if Text < 'Howdy' then
    // string comparison is True
>= operator

Greater than or equal, or superset. For numbers, strings, and PChar or PWideChar pointers, the >= operator is True when > is True or = is True. For sets, the >= operator tests whether all members of the right-hand operand are also members of the left-hand operand.

For example:

var
  A, B: set of 0..7;
begin
  A := [0, 1, 2, 4, 5, 6];
  B := [5, 7, 4];
  if A >= B then
    // False because (7 in A) is False
  B := [1, 2, 0]
  if A >= B then
    // True because all members of B are in A
<= operator

Less than or equal, or subset. For numbers, strings, and PChar or PWideChar pointers, the <= operator is True when < is True or = is True. For sets, the <= operator tests whether all members of the left-hand operand are also members of the right-hand operand. For example:

var
  A, B: set of 0..7;
begin
  A := [4, 5, 6];
  B := [5, 7, 4];
  if A <= B then
    // False because (6 in A) is False
  B := [5, 7, 6, 4]
  if A <= B then
    // True because all members of A are in B
In operator

Tests whether an element is a member of a set. See Chapter 5 for details.

Is operator

Tests the type of an object reference. See Chapter 5 for details. Note that is does not work on interfaces; call QueryInterface instead. (See also the Supports function in Appendix B.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset