Beginner

Control Flow in Delphi

Learn conditionals, case statements, and loops in Delphi (Object Pascal) with practical Docker-ready examples using Free Pascal in Delphi mode

Control flow is how a program decides what to do and how many times to do it. Delphi, built on Object Pascal, inherits Pascal’s famously clear and structured control-flow constructs: if/else for decisions, case for multi-way branching, and three distinct loop forms (for, while, and repeat). As a statically and strongly typed language, Delphi enforces these structures with explicit begin/end blocks rather than relying on indentation or braces.

What makes Delphi’s control flow distinctive is its readability and its emphasis on intent. A for loop counts in a fixed direction with to or downto, a while loop tests before running its body, and a repeat loop tests after — guaranteeing at least one execution. There is no fall-through in case statements (unlike C-style switch), which eliminates a whole category of bugs.

In this tutorial you will learn how to write conditionals, branch on values with case, iterate with all three loop types, and control loops using Break and Continue. Every example is a complete, runnable console program you can compile with Free Pascal in Delphi compatibility mode.

Conditionals: if / else if / else

The if statement evaluates a boolean expression and runs a branch accordingly. A key Delphi rule: because and, or, and not have higher precedence than comparison operators, you must wrap comparisons in parentheses when combining them.

Create a file named conditionals.dpr:

program Conditionals;

{$APPTYPE CONSOLE}

var
  Score: Integer;
  Grade: Char;

begin
  Score := 85;

  // Chained if / else if / else
  if Score >= 90 then
    Grade := 'A'
  else if Score >= 80 then
    Grade := 'B'
  else if Score >= 70 then
    Grade := 'C'
  else
    Grade := 'F';

  WriteLn('Score: ', Score, '  Grade: ', Grade);

  // Compound conditions need parentheses around each comparison
  if (Score >= 60) and (Score <= 100) then
    WriteLn('Passing score in valid range.');

  // A block of statements uses begin ... end
  if Grade = 'B' then
  begin
    WriteLn('Solid work.');
    WriteLn('Aim for an A next time.');
  end;
end.

Note that there is no semicolon before else — the if/else is a single statement. A common Pascal beginner mistake is writing then DoX; followed by else, which is a syntax error.

Multi-way Branching: the case Statement

The case statement selects one branch based on an ordinal value (integers, characters, enumerations, or booleans). Unlike C’s switch, there is no fall-through and no break is needed — exactly one branch runs. You can match single values, comma-separated lists, and ranges.

Create a file named case_statement.dpr:

program CaseStatement;

{$APPTYPE CONSOLE}

var
  Day: Integer;
  Letter: Char;

begin
  Day := 6;

  // Match single values, a list (6, 7), and an else fallback
  case Day of
    1: WriteLn('Monday');
    2: WriteLn('Tuesday');
    3: WriteLn('Wednesday');
    4: WriteLn('Thursday');
    5: WriteLn('Friday');
    6, 7: WriteLn('Weekend');
  else
    WriteLn('Invalid day');
  end;

  Letter := 'G';

  // case also works on characters, including ranges
  case Letter of
    'a'..'z': WriteLn('Lowercase letter');
    'A'..'Z': WriteLn('Uppercase letter');
    '0'..'9': WriteLn('Digit');
  else
    WriteLn('Other character');
  end;
end.

Counting Loops: for … to and for … downto

Delphi’s for loop is a counting loop. The control variable advances by exactly one each iteration — upward with to, downward with downto. The bounds are evaluated once at the start, and you must not modify the control variable inside the loop body.

Create a file named for_loops.dpr:

program ForLoops;

{$APPTYPE CONSOLE}

var
  I: Integer;
  Sum: Integer;
  C: Char;

begin
  // Count up from 1 to 5
  Write('Up:   ');
  for I := 1 to 5 do
    Write(I, ' ');
  WriteLn;

  // Count down from 5 to 1 with downto
  Write('Down: ');
  for I := 5 downto 1 do
    Write(I, ' ');
  WriteLn;

  // Accumulate a running total
  Sum := 0;
  for I := 1 to 10 do
    Sum := Sum + I;
  WriteLn('Sum of 1..10 = ', Sum);

  // for-in iterates over the characters of a string
  Write('Letters: ');
  for C in 'Delphi' do
    Write(C, '-');
  WriteLn;
end.

Conditional Loops: while and repeat

When the number of iterations is not known in advance, use while or repeat. The difference is when the condition is tested:

  • while tests the condition before the body, so the body may run zero times.
  • repeat ... until tests after the body, so it always runs at least once. Note that repeat loops until the condition becomes true (the opposite sense of while).

Create a file named while_repeat.dpr:

program WhileRepeat;

{$APPTYPE CONSOLE}

var
  N: Integer;

begin
  // while: test before the body runs
  N := 1;
  Write('Powers of 2: ');
  while N <= 16 do
  begin
    Write(N, ' ');
    N := N * 2;
  end;
  WriteLn;

  // repeat..until: body runs first, then the condition is tested
  N := 5;
  Write('Countdown:   ');
  repeat
    Write(N, ' ');
    Dec(N);
  until N = 0;
  WriteLn;
end.

Loop Control: Break and Continue

Break exits the innermost loop immediately. Continue skips the rest of the current iteration and moves to the next one. Both work in for, while, and repeat loops.

Create a file named loop_control.dpr:

program LoopControl;

{$APPTYPE CONSOLE}

var
  I: Integer;

begin
  // Continue: skip even numbers, print only odds
  Write('Odds:        ');
  for I := 1 to 10 do
  begin
    if I mod 2 = 0 then
      Continue;
    Write(I, ' ');
  end;
  WriteLn;

  // Break: stop as soon as we hit the first multiple of 7
  Write('Before 7x:   ');
  for I := 1 to 100 do
  begin
    if I mod 7 = 0 then
      Break;
    Write(I, ' ');
  end;
  WriteLn;
end.

Running with Docker

Each program compiles to an executable named after its source file (for example, conditionals.dpr produces ./conditionals). Use Free Pascal in Delphi mode with the -Mdelphi flag:

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

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

# Compile and run the case statement example
docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi case_statement.dpr && ./case_statement"

# Compile and run the for loops example
docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi for_loops.dpr && ./for_loops"

# Compile and run the while/repeat example
docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi while_repeat.dpr && ./while_repeat"

# Compile and run the loop control example
docker run --rm -v $(pwd):/app -w /app freepascal/fpc:3.2.2-slim \
    sh -c "fpc -Mdelphi loop_control.dpr && ./loop_control"

Expected Output

Running conditionals.dpr:

Score: 85  Grade: B
Passing score in valid range.
Solid work.
Aim for an A next time.

Running case_statement.dpr:

Weekend
Uppercase letter

Running for_loops.dpr:

Up:   1 2 3 4 5 
Down: 5 4 3 2 1 
Sum of 1..10 = 55
Letters: D-e-l-p-h-i-

Running while_repeat.dpr:

Powers of 2: 1 2 4 8 16 
Countdown:   5 4 3 2 1 

Running loop_control.dpr:

Odds:        1 3 5 7 9 
Before 7x:   1 2 3 4 5 6 

Key Concepts

  • No fall-through in case — exactly one branch runs, so you never need a break to stop one branch leaking into the next. Use comma lists (6, 7) and ranges ('a'..'z') to group matches.
  • Parenthesize compound conditions — because and/or/not bind tighter than comparison operators, if (a > 0) and (b > 0) needs both sets of parentheses or it won’t compile.
  • No semicolon before else — the entire if ... then ... else ... is one statement; a stray ; before else is a syntax error.
  • for is a counting loop — it steps by exactly one using to or downto. Don’t modify the control variable inside the body; use while when you need a custom step.
  • while vs repeatwhile tests before the body (may run zero times), while repeat ... until tests after (always runs at least once) and loops until the condition is true.
  • Break and ContinueBreak leaves the innermost loop; Continue jumps to the next iteration. Both apply to all three loop types.
  • begin/end group statements — a branch or loop body running more than one statement must be wrapped in a begin ... end block.
  • Ternary alternative — Delphi has no ?: operator, but IfThen (from the Math or StrUtils unit) gives you an inline IfThen(condition, valueIfTrue, valueIfFalse) expression.

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