Beginner

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:

LevelOperatorsCategory
1 (highest)not, @Unary
2*, /, div, mod, and, shl, shrMultiplicative
3+, -, or, xorAdditive
4 (lowest)=, <>, <, >, <=, >=, inRelational

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Pull the Free Pascal image
docker pull freepascal/fpc:3.2.2-slim

# Compile and run each example in Delphi mode
docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi operators_arithmetic.dpr && ./operators_arithmetic"

docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi operators_logical.dpr && ./operators_logical"

docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi operators_bitwise.dpr && ./operators_bitwise"

docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi operators_strings_sets.dpr && ./operators_strings_sets"

docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi operators_precedence.dpr && ./operators_precedence"

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: div for 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.
  • and and or sit at multiplicative/additive precedence, not below relational operators, so always parenthesize comparisons: (a < b) and (c < d).
  • Delphi has no compound assignment operators like +=. Use Inc(x, n) and Dec(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
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining