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.
@
operatorReturns 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
operatorLogical negation. See the not
keyword in Chapter 5 for details.
^
operatorPointer 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
+
operatorSign identity. The +
operator can be used before
any numeric expression. It has no effect, that is,
+7
=
7
.
-
operatorArithmetic 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.
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 := []
/
operatorFloating-point division. Dividing two integers converts the operands to floating point. Division by zero raises runtime error 7.
Div
operatorInteger division. See Chapter 5 for details.
Mod
operatorModulus (remainder). See Chapter 5 for details.
And
operatorLogical or bitwise conjunction. See Chapter 5 for details.
Shl
operatorLeft shift. See Chapter 5 for details.
Shr
operatorRight shift. See Chapter 5 for details.
As
operatorType check and cast of object and interface references. See Chapter 5 for details.
+
operatorAddition, 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'
-
operatorSubtraction, 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
operatorLogical or bitwise disjunction. See Chapter 5 for details.
Xor
operatorLogical or bitwise exclusive or. See Chapter 5 for details.
The comparison operators let you compare numbers, strings, sets, and pointers.
=
operatorEquality. 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.
<>
operatorInequality. Compare numbers, strings, or character pointers, and
sets. Returns the logical negation of the =
operator.
>
operatorGreater 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
<
operatorLess 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
>=
operatorGreater 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
<=
operatorLess 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
operatorTests whether an element is a member of a set. See Chapter 5 for details.
Is
operatorTests 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.)