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:
whiletests the condition before the body, so the body may run zero times.repeat ... untiltests after the body, so it always runs at least once. Note thatrepeatloops until the condition becomes true (the opposite sense ofwhile).
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:
| |
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 abreakto 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/notbind 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 entireif ... then ... else ...is one statement; a stray;beforeelseis a syntax error. foris a counting loop — it steps by exactly one usingtoordownto. Don’t modify the control variable inside the body; usewhilewhen you need a custom step.whilevsrepeat—whiletests before the body (may run zero times), whilerepeat ... untiltests after (always runs at least once) and loops until the condition is true.BreakandContinue—Breakleaves the innermost loop;Continuejumps to the next iteration. Both apply to all three loop types.begin/endgroup statements — a branch or loop body running more than one statement must be wrapped in abegin ... endblock.- Ternary alternative — Delphi has no
?:operator, butIfThen(from theMathorStrUtilsunit) gives you an inlineIfThen(condition, valueIfTrue, valueIfFalse)expression.
Running Today
All examples can be run using Docker:
docker pull freepascal/fpc:3.2.2-slim
Comments
Loading comments...
Leave a Comment