DART: Flow Control

Flow control statements determine the execution order of your Dart program. Dart provides the familiar if-else, switch-case, and five loop variants — each suited to a different iteration pattern. Understanding when and how to use each construct is fundamental to writing correct, readable Dart code.

Flow control is what separates a program from a simple list of instructions. It gives code the ability to make decisions, repeat actions, and skip over blocks based on conditions. Dart's flow control syntax is familiar to anyone coming from Java, C#, or JavaScript.


Conditional Statements

if / else if / else

The if statement evaluates a boolean condition. If the condition is true, the block executes. Optional else if and else branches handle alternative cases.

dart
int score = 75;

if (score >= 90) {
  print('Grade: A');
} else if (score >= 80) {
  print('Grade: B');
} else if (score >= 70) {
  print('Grade: C');
} else {
  print('Grade: F');
}
// Output: Grade: C

Conditions can use any expression that evaluates to a bool:

dart
String? username;

if (username == null) {
  print('Not logged in');
} else if (username.isEmpty) {
  print('Username is blank');
} else {
  print('Welcome, $username!');
}


switch / case

The switch statement is useful when comparing a single value against multiple known cases. It is more readable than a long chain of if-else if when many discrete values are possible.

dart
int day = 3;

switch (day) {
  case 1:
    print('Monday');
    break;
  case 2:
    print('Tuesday');
    break;
  case 3:
    print('Wednesday');
    break;
  case 6:
  case 7:
    print('Weekend');  // Fall-through: matches 6 OR 7
    break;
  default:
    print('Unknown day');
}
// Output: Wednesday

Important: Each non-empty case block must end with break, return, throw, or continue. Dart does not allow implicit fall-through between non-empty cases.

dart
String status = 'active';

switch (status) {
  case 'active':
    print('User is active');
    break;
  case 'suspended':
    print('User is suspended');
    break;
  case 'deleted':
    print('User is deleted');
    break;
  default:
    print('Unknown status: $status');
}


Loops

Dart provides five loop constructs. Choosing the right one improves both readability and intent.

md
Loop Types
-----------
for         --> Known number of iterations
for-in      --> Iterate over every element in a collection
forEach     --> Functional iteration with a callback
while       --> Iterate while a condition is true
do-while    --> Iterate at least once, then check condition


Standard for Loop

Use the classic for loop when you need the index or when iterating a specific number of times.

dart
// Counting up
for (int i = 1; i <= 5; i++) {
  print(i);  // 1, 2, 3, 4, 5
}

// Counting down
for (int i = 5; i > 0; i--) {
  print(i);  // 5, 4, 3, 2, 1
}

// With step
for (int i = 0; i <= 10; i += 2) {
  print(i);  // 0, 2, 4, 6, 8, 10
}


for-in Loop

Use for-in when you want every element of a collection but do not need the index. It is more readable than a standard for loop for simple iteration.

dart
List<String> fruits = ['Apple', 'Banana', 'Cherry'];

for (var fruit in fruits) {
  print(fruit);
}
// Output: Apple, Banana, Cherry

Set<int> primes = {2, 3, 5, 7, 11};

for (var prime in primes) {
  print(prime);
}


forEach

The forEach method on collections accepts a function and calls it once for each element. It is idiomatic Dart for functional-style iteration.

dart
List<String> names = ['Alice', 'Bob', 'Charlie'];

// Using a named function
void printName(String name) {
  print(name);
}
names.forEach(printName);

// Using a lambda (anonymous function)
names.forEach((name) => print(name));

// With an arrow function
names.forEach(print);  // Most concise form


while Loop

The while loop checks its condition before each iteration. If the condition starts as false, the body never executes.

dart
int countdown = 5;

while (countdown > 0) {
  print(countdown);
  countdown--;
}
print('Blast off!');
// Output: 5, 4, 3, 2, 1, Blast off!

Use while when the number of iterations is not known in advance and the condition might be false from the start.


do-while Loop

The do-while loop executes the body once before checking the condition. This guarantees at least one iteration.

dart
int num = 0;

do {
  print(num);
  num++;
} while (num < 5);
// Output: 0, 1, 2, 3, 4

A common use case is prompting the user until they provide valid input:

dart
String? input;

do {
  input = getUserInput();  // Always ask at least once
} while (input == null || input.isEmpty);


Loop Control: break and continue

break

Immediately exits the loop, skipping all remaining iterations.

dart
List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

for (var n in numbers) {
  if (n == 6) break;  // Stop when we reach 6
  print(n);
}
// Output: 1, 2, 3, 4, 5

continue

Skips the current iteration and moves to the next one, without exiting the loop.

dart
for (int i = 1; i <= 10; i++) {
  if (i % 2 == 0) continue;  // Skip even numbers
  print(i);
}
// Output: 1, 3, 5, 7, 9


Choosing the Right Construct

md
Decision Guide
--------------
Single condition?
  --> if/else

Multiple discrete values?
  --> switch/case

Known number of iterations?
  --> for

Iterating a collection (no index needed)?
  --> for-in or forEach

Unknown iterations, condition-first?
  --> while

Must execute at least once?
  --> do-while

Using the most appropriate construct makes code intent immediately clear to the reader — and to your future self.