Operators in Delphi
Learn arithmetic, comparison, logical, bitwise, and set operators in Delphi with practical Free Pascal examples
Operators are the building blocks of every expression. Delphi inherits its operator set from Pascal but adds modern features that make it expressive and safe. Because Delphi is statically and strongly typed, the compiler enforces operator compatibility at compile time — you cannot accidentally add a string to an integer the way you can in dynamic languages.
A distinctive trait of Delphi’s operator design is the use of English-language keywords for logical and bitwise operations (and, or, not, xor, div, mod) rather than the symbolic forms common in C-family languages. Delphi also separates integer division (div) from floating-point division (/), preventing a common class of arithmetic bugs.
In this tutorial you will learn arithmetic, relational, logical, bitwise, string, and set operators, plus how operator precedence interacts with Delphi’s expression evaluation.
Arithmetic Operators
Delphi distinguishes carefully between integer and real arithmetic. The / operator always produces a Real, while div and mod only operate on integers.
Create a file named operators_arithmetic.dpr:
program OperatorsArithmetic;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
A, B: Integer;
X, Y: Double;
begin
A := 17;
B := 5;
WriteLn('Integer arithmetic with A=17, B=5');
WriteLn('A + B = ', A + B);
WriteLn('A - B = ', A - B);
WriteLn('A * B = ', A * B);
WriteLn('A div B = ', A div B); // integer division
WriteLn('A mod B = ', A mod B); // remainder
WriteLn('-A = ', -A);
X := 10.0;
Y := 4.0;
WriteLn;
WriteLn('Real arithmetic with X=10.0, Y=4.0');
WriteLn(Format('X / Y = %.4f', [X / Y]));
WriteLn(Format('Sqrt(X) = %.4f', [Sqrt(X)]));
end.
The split between / and div is deliberate. Writing A / B when A and B are both Integer returns a Real (here, 3.4), while A div B returns the integer quotient 3. The compiler will refuse to assign A / B to an Integer variable without an explicit conversion.
Comparison and Logical Operators
Delphi’s logical operators are spelled out — and, or, not, xor — and they work on both boolean values and integer bit patterns depending on operand types.
Create a file named operators_logical.dpr:
program OperatorsLogical;
{$APPTYPE CONSOLE}
var
Age: Integer;
HasLicense, IsAdult, CanDrive: Boolean;
begin
Age := 19;
HasLicense := True;
IsAdult := Age >= 18;
CanDrive := IsAdult and HasLicense;
WriteLn('Age = ', Age);
WriteLn('IsAdult = ', IsAdult);
WriteLn('HasLicense = ', HasLicense);
WriteLn('CanDrive = ', CanDrive);
WriteLn('Not CanDrive = ', not CanDrive);
// Comparison operators produce Boolean results
WriteLn('5 = 5 -> ', 5 = 5); // equality uses single =
WriteLn('5 <> 4 -> ', 5 <> 4); // inequality
WriteLn('5 < 10 -> ', 5 < 10);
WriteLn('True xor False -> ', True xor False);
end.
Note that equality is =, not ==. Inequality is <>. This is one of the most common stumbling blocks for developers arriving from C-style languages. The single = is unambiguous in Delphi because assignment uses :=.
Bitwise Operators and Short-Circuit Evaluation
The same keywords (and, or, not, xor) act as bitwise operators when applied to integer operands. Delphi also provides shl and shr for shifts.
Create a file named operators_bitwise.dpr:
program OperatorsBitwise;
{$APPTYPE CONSOLE}
{$BOOLEVAL OFF} // ensure short-circuit boolean evaluation (the default)
uses
SysUtils;
var
Flags, Mask: Word;
Divisor: Integer;
begin
Flags := $0F; // binary 0000 1111
Mask := $33; // binary 0011 0011
WriteLn(Format('Flags = $%2.2x', [Flags]));
WriteLn(Format('Mask = $%2.2x', [Mask]));
WriteLn(Format('Flags and Mask = $%2.2x', [Flags and Mask]));
WriteLn(Format('Flags or Mask = $%2.2x', [Flags or Mask]));
WriteLn(Format('Flags xor Mask = $%2.2x', [Flags xor Mask]));
WriteLn(Format('Flags shl 2 = $%2.2x', [Flags shl 2]));
WriteLn(Format('Flags shr 1 = $%2.2x', [Flags shr 1]));
// Short-circuit evaluation prevents the divide-by-zero
Divisor := 0;
if (Divisor <> 0) and (10 div Divisor > 1) then
WriteLn('Branch taken')
else
WriteLn('Short-circuit skipped the second test');
end.
The {$BOOLEVAL OFF} directive (the default in Delphi mode) makes and / or short-circuit when used with booleans, just like && / || in C. With {$BOOLEVAL ON} Delphi will evaluate both operands fully — useful when each operand has a deliberate side effect.
String, Set, and Assignment Operators
Delphi treats strings as first-class values. The + operator concatenates them, and dedicated set operators (in, +, -, *) provide a concise way to work with small enumerated collections.
Create a file named operators_strings_sets.dpr:
program OperatorsStringsSets;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TWeekDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
TDaySet = set of TWeekDay;
var
Greeting, Subject: string;
Counter: Integer;
Workdays, Weekend, AllDays: TDaySet;
begin
// String concatenation with +
Greeting := 'Hello';
Subject := 'Delphi';
WriteLn(Greeting + ', ' + Subject + '!');
// Compound assignment via Inc/Dec (Delphi has no +=, but these are idiomatic)
Counter := 10;
Inc(Counter, 5); // Counter := Counter + 5
Dec(Counter); // Counter := Counter - 1
WriteLn('Counter = ', Counter);
// Sets: a Delphi specialty
Workdays := [Mon, Tue, Wed, Thu, Fri];
Weekend := [Sat, Sun];
AllDays := Workdays + Weekend; // set union
WriteLn('Wed in Workdays -> ', Wed in Workdays);
WriteLn('Sat in Workdays -> ', Sat in Workdays);
WriteLn('Union size = ', Ord(High(TWeekDay)) - Ord(Low(TWeekDay)) + 1);
WriteLn('Intersection empty? ', (Workdays * Weekend) = []);
end.
The in operator tests set membership, + unions two sets, - subtracts, and * intersects. Sets are limited to small ordinal base types (typically 256 elements) but are extremely fast — they compile down to bitmask operations.
Operator Precedence
Delphi groups operators into four precedence levels, from highest to lowest:
| Level | Operators | Category |
|---|---|---|
| 1 (highest) | not, @ | Unary |
| 2 | *, /, div, mod, and, shl, shr | Multiplicative |
| 3 | +, -, or, xor | Additive |
| 4 (lowest) | =, <>, <, >, <=, >=, in | Relational |
A common surprise: and is multiplicative-level, not lower than comparison. This means A < B and C < D parses as A < (B and C) < D, which is a type error. Always parenthesize compound boolean expressions:
if (A < B) and (C < D) then ...
Create a file named operators_precedence.dpr:
program OperatorsPrecedence;
{$APPTYPE CONSOLE}
var
R: Integer;
A, B, C, D: Integer;
begin
// Multiplicative binds tighter than additive
R := 2 + 3 * 4;
WriteLn('2 + 3 * 4 = ', R); // 14
R := (2 + 3) * 4;
WriteLn('(2 + 3) * 4 = ', R); // 20
// div and mod sit at the multiplicative level
R := 20 - 6 div 2;
WriteLn('20 - 6 div 2 = ', R); // 17
A := 1; B := 2; C := 3; D := 4;
// Parentheses are required around comparisons combined with logical ops
if (A < B) and (C < D) then
WriteLn('Both comparisons true');
end.
Running with Docker
| |
Expected Output
Running operators_arithmetic:
Integer arithmetic with A=17, B=5
A + B = 22
A - B = 12
A * B = 85
A div B = 3
A mod B = 2
-A = -17
Real arithmetic with X=10.0, Y=4.0
X / Y = 2.5000
Sqrt(X) = 3.1623
Running operators_logical:
Age = 19
IsAdult = TRUE
HasLicense = TRUE
CanDrive = TRUE
Not CanDrive = FALSE
5 = 5 -> TRUE
5 <> 4 -> TRUE
5 < 10 -> TRUE
True xor False -> TRUE
Running operators_bitwise:
Flags = $0f
Mask = $33
Flags and Mask = $03
Flags or Mask = $3f
Flags xor Mask = $3c
Flags shl 2 = $3c
Flags shr 1 = $07
Short-circuit skipped the second test
Running operators_strings_sets:
Hello, Delphi!
Counter = 14
Wed in Workdays -> TRUE
Sat in Workdays -> FALSE
Union size = 7
Intersection empty? TRUE
Running operators_precedence:
2 + 3 * 4 = 14
(2 + 3) * 4 = 20
20 - 6 div 2 = 17
Both comparisons true
Key Concepts
- Assignment is
:=, equality is=— Delphi avoids the C-style=vs==confusion entirely. - Integer vs real division are separate operators:
divfor integer quotient,/for floating-point. The compiler enforces this distinction. - Logical operators are keywords (
and,or,not,xor) and double as bitwise operators when applied to integers. - Boolean evaluation short-circuits by default under
{$BOOLEVAL OFF}(the standard Delphi mode), so guards like(p <> nil) and (p^.value > 0)are safe. - Sets are a first-class feature with
in,+,-, and*operators — extremely efficient for small enumerated types. andandorsit at multiplicative/additive precedence, not below relational operators, so always parenthesize comparisons:(a < b) and (c < d).- Delphi has no compound assignment operators like
+=. UseInc(x, n)andDec(x, n)for integer counters — they compile to the same machine code. - String concatenation uses
+, and modern Delphi strings are dynamic and reference-counted, so concatenation is safe and efficient.
Running Today
All examples can be run using Docker:
docker pull freepascal/fpc:3.2.2-slim
Comments
Loading comments...
Leave a Comment