RAD Studio (Common)

circuit evaluation is usually preferable because it guarantees minimum execution time and, in most cases, minimum code size. Complete evaluation is sometimes convenient when one operand is a function with side effects that alter the execution of the program.
circuit evaluation also allows the use of constructions that might otherwise result in illegal runtime operations. For example, the following code iterates through the string S, up to the first comma.
while (I <= Length(S)) and (S[I] <> ',') do begin ... Inc(I); end;
In the case where S has no commas, the last iteration increments I to a value which is greater than the length of S. When the while condition is next tested, complete evaluation results in an attempt to read S[I], which could cause a runtime error. Under shortcircuit evaluation, in contrast, the second part of the while condition (S[I] <> ',') is not evaluated after the first part fails.
Use the $B compiler directive to control evaluation mode. The default state is {$B}, which enables shortcircuit evaluation. To enable complete evaluation locally, add the {$B+} directive to your code. You can also switch to complete evaluation on a projectwide basis by selecting Complete Boolean Evaluation in the Compiler Options dialog (all source units will need to be recompiled).
The following logical operators perform bitwise manipulation on integer operands. For example, if the value stored in X (in binary) is 001101 and the value stored in Y is 100001, the statement:
Z := X or Y;
assigns the value 101101 to Z.
Logical (Bitwise) Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
not 
bitwise negation 
integer 
integer 
not X 
and 
bitwise and 
integer 
integer 
X and Y 
or 
bitwise or 
integer 
integer 
X or Y 
xor 
bitwise xor 
integer 
integer 
X xor Y 
shl 
bitwise shift left 
integer 
integer 
X shl 2 
shr 
bitwise shift right 
integer 
integer 
Y shr I 
The following rules apply to bitwise operators.
The relational operators =, <>, <, >, <=, and >= all take string operands (see Relational operators). The + operator concatenates two strings.
String Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
+ 
concatenation 
string, packed string, character 
string 
S + '.' 
The following rules apply to string concatenation.
The relational operators <, >, <=, and >= can take operands of type PAnsiChar and PWideChar (see Relational operators). The following operators also take pointers as operands. For more information about pointers, see Pointers and pointer types.
Characterpointer operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
+ 
pointer addition 
character pointer, integer 
character pointer 
P + I 
 
pointer subtraction 
character pointer, integer 
character pointer, integer 
P  Q 
^ 
pointer dereference 
pointer 
base type of pointer 
P^ 
= 
equality 
pointer 
Boolean 
P = Q 
<> 
inequality 
pointer 
Boolean 
P <>Q 
The ^ operator dereferences a pointer. Its operand can be a pointer of any type except the generic Pointer, which must be typecast before dereferencing.
P = Q is True just in case P and Q point to the same address; otherwise, P <> Q is True.
You can use the + and  operators to increment and decrement the offset of a character pointer. You can also use  to calculate the difference between the offsets of two character pointers. The following rules apply.
The following operators take sets as operands.
Set Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
+ 
union 
set 
set 
Set1 + Set2 
 
difference 
set 
set 
S  T 
* 
intersection 
set 
set 
S * T 
<= 
subset 
set 
Boolean 
Q <= MySet 
>= 
superset 
set 
Boolean 
S1 >= S2 
= 
equality 
set 
Boolean 
S2 = MySet 
<> 
inequality 
set 
Boolean 
MySet <> S1 
in 
membership 
ordinal, set 
Boolean 
A in Set1 
The following rules apply to +, , and *.
Relational operators are used to compare two operands. The operators =, <>, <=, and >= also apply to sets.
Relational Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
= 
equality 
simple, class, class reference, interface, string, packed string 
Boolean 
I = Max 
<> 
inequality 
simple, class, class reference, interface, string, packed string 
Boolean 
X <> Y 
< 
lessthan 
simple, string, packed string, PChar 
Boolean 
X < Y 
> 
greaterthan 
simple, string, packed string, PChar 
Boolean 
Len > 0 
<= 
lessthanorequalto 
simple, string, packed string, PChar 
Boolean 
Cnt <= I 
>= 
greaterthanorequalto 
simple, string, packed string, PChar 
Boolean 
I >= 1 
For most simple types, comparison is straightforward. For example, I = J is True just in case I and J have the same value, and I <> J is True otherwise. The following rules apply to relational operators.
The operators as and is take classes and instance objects as operands; as operates on interfaces as well. For more information, see Classes and objects and Object interfaces.
The relational operators = and <> also operate on classes.
The @ operator returns the address of a variable, or of a function, procedure, or method; that is, @ constructs a pointer to its operand. For more information about pointers, see Pointers and pointer types. The following rules apply to @.
@TMyClass.DoSomething
points to the DoSomething method of TMyClass. For more information about classes and methods, see Classes and objects.
In complex expressions, rules of precedence determine the order in which operations are performed.
Precedence of operators
Operators 
Precedence 
@, not 
first (highest) 
*, /, div, mod, and, shl, shr, as 
second 
+, , or, xor 
third 
=, <>, <, >, <=, >=, in, is 
fourth (lowest) 
An operator with higher precedence is evaluated before an operator with lower precedence, while operators of equal precedence associate to the left. Hence the expression
X + Y * Z
multiplies Y times Z, then adds X to the result; * is performed first, because is has a higher precedence than +. But
X  Y + Z
first subtracts Y from X, then adds Z to the result;  and + have the same precedence, so the operation on the left is performed first.
You can use parentheses to override these precedence rules. An expression within parentheses is evaluated first, then treated as a single operand. For example,
(X + Y) * Z
multiplies Z times the sum of X and Y.
Parentheses are sometimes needed in situations where, at first glance, they seem not to be. For example, consider the expression
X = Y or X = Z
The intended interpretation of this is obviously
(X = Y) or (X = Z)
Without parentheses, however, the compiler follows operator precedence rules and reads it as
(X = (Y or X)) = Z
which results in a compilation error unless Z is Boolean.
Parentheses often make code easier to write and to read, even when they are, strictly speaking, superfluous. Thus the first example could be written as
X + (Y * Z)
Here the parentheses are unnecessary (to the compiler), but they spare both programmer and reader from having to think about operator precedence.
This topic describes syntax rules of forming Delphi expressions.
The following items are covered in this topic:
An expression is a construction that returns a value. The following table shows examples of Delphi expressions:
X 
variable 
@X 
address of the variable X 
15 
integer constant 
InterestRate 
variable 
Calc(X, Y) 
function call 
X * Y 
product of X and Y 
Z / (1  Z) 
quotient of Z and (1  Z) 
X = 1.5 
Boolean 
C in Range1 
Boolean 
not Done 
negation of a Boolean 
['a', 'b', 'c'] 
set 
Char(48) 
value typecast 
The simplest expressions are variables and constants (described in Data types). More complex expressions are built from simpler ones using operators, function calls, set constructors, indexes, and typecasts.
Operators behave like predefined functions that are part of the Delphi language. For example, the expression (X + Y) is built from the variables X and Y, called operands, with the + operator; when X and Y represent integers or reals, (X + Y) returns their sum. Operators include @, not, ^, *, /, div, mod, and, shl, shr, as, +, , or, xor, =, >, <, <>, <=, >=, in, and is.
The operators @, not, and ^ are unary (taking one operand). All other operators are binary (taking two operands), except that + and  can function as either a unary or binary operator. A unary operator always precedes its operand (for example, B), except for ^, which follows its operand (for example, P^). A binary operator is placed between its operands (for example, A = 7).
Some operators behave differently depending on the type of data passed to them. For example, not performs bitwise negation on an integer operand and logical negation on a Boolean operand. Such operators appear below under multiple categories.
Except for ^, is, and in, all operators can take operands of type Variant.
The sections that follow assume some familiarity with Delphi data types.
For information about operator precedence in complex expressions, see Operator Precedence Rules, later in this topic.
Arithmetic operators, which take real or integer operands, include +, , *, /, div, and mod.
Binary Arithmetic Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
+ 
addition 
integer, real 
integer, real 
X + Y 
 
subtraction 
integer, real 
integer, real 
Result 1 
* 
multiplication 
integer, real 
integer, real 
P * InterestRate 
/ 
real division 
integer, real 
real 
X / 2 
div 
integer division 
integer 
integer 
Total div UnitSize 
mod 
remainder 
integer 
integer 
Y mod 6 
Unary arithmetic operators
Operator 
Operation 
Operand Type 
Result Type 
Example 
+ 
sign identity 
integer, real 
integer, real 
+7 
 
sign negation 
integer, real 
integer, real 
X 
The following rules apply to arithmetic operators.
The Boolean operators not, and, or, and xor take operands of any Boolean type and return a value of type Boolean.
Boolean Operators
Operator 
Operation 
Operand Types 
Result Type 
Example 
not 
negation 
Boolean 
Boolean 
not (C in MySet) 
and 
conjunction 
Boolean 
Boolean 
Done and (Total >0) 
or 
disjunction 
Boolean 
Boolean 
A or B 
xor 
exclusive disjunction 
Boolean 
Boolean 
A xor B 
These operations are governed by standard rules of Boolean logic. For example, an expression of the form x and y is True if and only if both x and y are True.
The compiler supports two modes of evaluation for the and and or operators: complete evaluation and shortcircuit (partial) evaluation. Complete evaluation means that each conjunct or disjunct is evaluated, even when the result of the entire expression is already determined. Shortcircuit evaluation means strict lefttoright evaluation that stops as soon as the result of the entire expression is determined. For example, if the expression A and B is evaluated under shortcircuit mode when A is False, the compiler won't evaluate B; it knows that the entire expression is False as soon as it evaluates A.
Because functions return a value, function calls are expressions. For example, if you've defined a function called Calc that takes two integer arguments and returns an integer, then the function call Calc(24,47) is an integer expression. If I and J are integer variables, then I + Calc(J,8) is also an integer expression. Examples of function calls include
Sum(A, 63) Maximum(147, J) Sin(X + Y) Eof(F) Volume(Radius, Height) GetValue TSomeObject.SomeMethod(I,J);
For more information about functions, see Procedures and functions.
A set constructor denotes a settype value. For example,
[5, 6, 7, 8]
denotes the set whose members are 5, 6, 7, and 8. The set constructor
[ 5..8 ]
could also denote the same set.
The syntax for a set constructor is
[ item1, ..., itemn ]
where each item is either an expression denoting an ordinal of the set's base type or a pair of such expressions with two dots (..) in between. When an item has the form x..y, it is shorthand for all the ordinals in the range from x to y, including y; but if x is greater than y, then x..y, the set [x..y], denotes nothing and is the empty set. The set constructor [ ] denotes the empty set, while [x] denotes the set whose only member is the value of x.
Examples of set constructors:
[red, green, MyColor] [1, 5, 10..K mod 12, 23] ['A'..'Z', 'a'..'z', Chr(Digit + 48)]
For more information about sets, see Sets.
Strings, arrays, array properties, and pointers to strings or arrays can be indexed. For example, if FileName is a string variable, the expression FileName[3] returns the third character in the string denoted by FileName, while FileName[I + 1] returns the character immediately after the one indexed by I. For information about strings, see String types. For information about arrays and array properties, see Arrays and Array properties.
It is sometimes useful to treat an expression as if it belonged to different type. A typecast allows you to do this by, in effect, temporarily changing an expression's type. For example, Integer('A') casts the character A as an integer.
The syntax for a typecast is
typeIdentifier(expression)
If the expression is a variable, the result is called a variable typecast; otherwise, the result is a value typecast. While their syntax is the same, different rules apply to the two kinds of typecast.
In a value typecast, the type identifier and the cast expression must both be ordinal or pointer types. Examples of value typecasts include
Integer('A') Char(48) Boolean(0) Color(2) Longint(@Buffer)
The resulting value is obtained by converting the expression in parentheses. This may involve truncation or extension if the size of the specified type differs from that of the expression. The expression's sign is always preserved.
The statement
I := Integer('A');
assigns the value of Integer('A'), which is 65, to the variable I.
A value typecast cannot be followed by qualifiers and cannot appear on the left side of an assignment statement.
You can cast any variable to any type, provided their sizes are the same and you do not mix integers with reals. (To convert numeric types, rely on standard functions like Int and Trunc.) Examples of variable typecasts include
Char(I) Boolean(Count) TSomeDefinedType(MyVariable)
Variable typecasts can appear on either side of an assignment statement. Thus
var MyChar: char; ... Shortint(MyChar) := 122;
assigns the character z (ASCII 122) to MyChar.
You can cast variables to a procedural type. For example, given the declarations
type Func = function(X: Integer): Integer; var F: Func; P: Pointer; N: Integer;
you can make the following assignments.
F := Func(P); { Assign procedural value in P to F } Func(P) := F; { Assign procedural value in F to P } @F := P; { Assign pointer value in P to F } P := @F; { Assign pointer value in F to P } N := F(N); { Call function via F } N := Func(P)(N); { Call function via P }
Variable typecasts can also be followed by qualifiers, as illustrated in the following example.
type TByteRec = record Lo, Hi: Byte; end; TWordRec = record Low, High: Word; end; var B: Byte; W: Word; L: Longint; P: Pointer; begin W := $1234; B := TByteRec(W).Lo; TByteRec(W).Hi := 0; L := $1234567; W := TWordRec(L).Low; B := TByteRec(TWordRec(L).Low).Hi; B := PByte(L)^; end;
In this example, TByteRec is used to access the low and highorder bytes of a word, and TWordRec to access the low and highorder words of a long integer. You could call the predefined functions Lo and Hi for the same purpose, but a variable typecast has the advantage that it can be used on the left side of an assignment statement.
For information about typecasting pointers, see Pointers and pointer types. For information about casting class and interface types, see The as operator and Interface typecasts.
Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.

What do you think about this topic? Send feedback!
