Watch the video (16 min)
On this page25 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. The if-else Statement
  5. 2. else Has No Condition
  6. 3. Many Options with else if
  7. 4. Order Matters
  8. 5. The Final else Is Optional
  9. 6. Nested if
  10. 7. Flattening a Nested if
  11. 8. Assigning a Value in Every Branch
  12. 9. Promotion in the else Branch
  13. 10. Revisiting the Conditional Expression
  14. 11. Choosing Between if-else and ? :
  15. 12. Chained ? : versus else if
  16. 13. A Real-World Example
  17. Code Examples
  18. Common Beginner Mistakes
  19. Best Practices
  20. Mini Challenge
  21. Practice Questions
  22. Practice Answers
  23. Quick Revision
  24. Key Takeaways
  25. What's Next?

Lecture 23 — if-else, else-if & Conditional Expressions

Category5 — Control Flow
Lecture023 of 140
Estimated video length16 min
TargetDart 3.12.2
LevelBeginner

A single if can only say "do this, or do nothing". With else and else if, a program picks exactly one path out of two, three, or ten — and ? : does the same for a value.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.


Prerequisites

Students should already understand, from Lectures 004–022:

  • variables, var, final, and string interpolation with $ and ${...}
  • nullable types such as String? and int.tryParse (Lectures 012–013)
  • comparison operators and logical operators &&, ||, ! (Lectures 018–019)
  • the conditional expression condition ? a : b (Lecture 020)
  • the if statement, its condition, its { } block, and promotion after != null (Lecture 022)

Connection With Previous Lectures

In Lecture 022, an if ran its block only when the condition was true. To report both results — pass or fail — we would need two ifs:

dart
if (mark >= 50) {
  print('Pass');
}
if (mark < 50) {
  print('Fail');
}

This works, but asks the same question twice, once backwards. Change 50 to 40 in one line and forget the other, and a mark of 45 prints both words. What we mean is one decision with two outcomes. Dart has a word for "otherwise": else.


Learning Objectives

By the end of this lecture you will be able to:

  • Write an if-else statement that runs exactly one of two blocks
  • Build an else-if chain that chooses between many options
  • Order the conditions in a chain so the right branch wins
  • Nest an if inside another, and flatten it when that reads better
  • Give a variable its value in every branch of an if-else
  • Use promotion after a null check in the else branch
  • Compare if-else with the conditional expression ? : and choose between them
  • Recognize the errors and silent bugs that else mistakes cause

1. The if-else Statement

output
if (condition) {
  // runs when condition is true
} else {
  // runs when condition is false
}
dart
void main() {
  var mark = 42;
  if (mark >= 50) {
    print('Pass');
  } else {
    print('Fail');
  }
}
output
Fail

Analogy — a fork in a road. You must take one branch, and you cannot take both. if is the left branch, else is the right branch.

Exactly one block runs, every time. else means "in every other case".


2. else Has No Condition

else already means "the condition was false", so it never takes a condition of its own. Writing one confuses Dart badly:

dart
void main() {
  var mark = 40;
  if (mark >= 50) {
    print('Pass');
  } else (mark < 50) { // ✗
    print('Fail');
  }
}
output
Error: Expected ')' before this.
  } else (mark < 50) { // ✗
               ^
Error: Expected ';' after this.
  }
  ^

The messages point at odd places, because Dart tried to read (mark < 50) { as a separate statement. For a second condition, use else if.


3. Many Options with else if

Real decisions often have more than two outcomes. An else-if chain asks one question after another:

dart
void main() {
  var mark = 72;
  if (mark >= 80) {
    print('Grade A');
  } else if (mark >= 60) {
    print('Grade B');
  } else if (mark >= 50) {
    print('Grade C');
  } else {
    print('Grade F');
  }
}
output
Grade B

Dart checks the conditions from top to bottom. 72 >= 80 is false, so it moves on. 72 >= 60 is true, so it prints Grade B — and skips everything else in the chain, even though 72 >= 50 is also true. The first true condition wins.


4. Order Matters

Because the first true condition wins, a chain in the wrong order gives wrong answers with no error message:

dart
void main() {
  var mark = 95;
  if (mark >= 50) {
    print('Grade C');
  } else if (mark >= 80) {
    print('Grade A');
  } else {
    print('Grade F');
  }
}
output
Grade C

A mark of 95 stops at the first test, 95 >= 50, and never reaches the A branch. When conditions overlap, put the narrowest one first: the highest mark, then the next.


5. The Final else Is Optional

A chain may end without an else. Then, if no condition is true, nothing runs at all:

dart
void main() {
  var temperature = 22;
  if (temperature >= 35) {
    print('Heat warning!');
  } else if (temperature <= 0) {
    print('Frost warning!');
  }
  print('Forecast done.');
}
output
Forecast done.

Leave out the else when "none of these" means "nothing to do". Keep it when every case needs an answer, like a grade.


6. Nested if

A block can contain any statements — including another if. That is a nested if:

dart
void main() {
  var age = 20;
  var hasTicket = false;
  if (age >= 18) {
    if (hasTicket) {
      print('Welcome in!');
    } else {
      print('Please buy a ticket.');
    }
  } else {
    print('Adults only.');
  }
}
output
Please buy a ticket.

Only adults reach the inner question about the ticket. Each else belongs to the if whose block it closes — the braces make that clear.

Editor hint. When a bool variable is set straight to true or false, as in many programs in this lecture, your editor may grey out a branch with the hint "Dead code". Dart can see that branch can never run with this value. The program still works; in real programs the value comes from input, and every branch is live.


7. Flattening a Nested if

A flat else-if chain is often easier to read. This program gives the same answers:

dart
void main() {
  var age = 20;
  var hasTicket = false;
  if (age < 18) {
    print('Adults only.');
  } else if (hasTicket) {
    print('Welcome in!');
  } else {
    print('Please buy a ticket.');
  }
}
output
Please buy a ticket.

Reaching else if (hasTicket) already means age < 18 was false. A flat chain reads like a list of rules.


8. Assigning a Value in Every Branch

Often each branch decides a value. Declare the variable first, then assign it in every branch. It can even be final, because each run assigns it exactly once:

dart
void main() {
  var mark = 72;
  final String result;
  if (mark >= 50) {
    result = 'Pass';
  } else {
    result = 'Fail';
  }
  print(result);
}
output
Pass

Dart checks that every path gives the variable a value. Remove the final else from a chain, and one path is left without a value:

dart
void main() {
  var mark = 72;
  String grade;
  if (mark >= 80) {
    grade = 'A';
  } else if (mark >= 60) {
    grade = 'B';
  }
  print(grade); // ✗
}
output
Error: Non-nullable variable 'grade' must be assigned before it can be used.
  print(grade); // ✗
        ^^^^^

Dart does not look at the value 72: a mark below 60 would reach print with no grade. Adding else { grade = 'C'; } fixes it.


9. Promotion in the else Branch

In Lecture 022, Dart promoted a nullable variable inside if (x != null). After if (x == null), the same happens in the else branch:

dart
void main() {
  var input = 'Zed';
  String? nickname = input.isEmpty ? null : input;
  if (nickname == null) {
    print('No nickname set.');
  } else {
    print('Nickname has ${nickname.length} letters.');
  }
}
output
Nickname has 3 letters.

nickname.length would be rejected on a String?. Inside else, the null case is already handled, so it is allowed — no ! needed.


10. Revisiting the Conditional Expression

In Lecture 020 you met condition ? a : b. It asks the same yes-or-no question as if-else, but it produces a value instead of running blocks. Here is one decision written both ways:

dart
void main() {
  var mark = 72;

  String result1;
  if (mark >= 50) {
    result1 = 'Pass';
  } else {
    result1 = 'Fail';
  }

  var result2 = mark >= 50 ? 'Pass' : 'Fail';

  print(result1);
  print(result2);
}
output
Pass
Pass

if-else is a statement: it does things. ? : is an expression: it is a value, so it fits after = or inside ${...}, where an if statement cannot go.


11. Choosing Between if-else and ? :

Use ? : when…Use if-else when…
you choose between two valuesyou choose between actions (statements)
each side is shorta branch needs several lines
the result goes into a variable or ${...}there are three or more outcomes

When each branch does more than produce one value, if-else is the right tool:

dart
void main() {
  var balance = 300;
  var price = 450;
  if (balance >= price) {
    balance -= price;
    print('Paid $price. Balance: $balance');
  } else {
    var missing = price - balance;
    print('Declined. You need $missing more.');
  }
}
output
Declined. You need 150 more.

The else branch holds two statements, which a conditional expression cannot.


12. Chained ? : versus else if

In Lecture 021 you saw that ? : can be chained:

dart
void main() {
  var mark = 72;

  var grade = mark >= 80
      ? 'A'
      : mark >= 60
      ? 'B'
      : 'C';
  print(grade);
}
output
B

It is correct, but compare it with the chain in section 3: the else-if version shows each rule on its own line. A good habit: one ? per expression. For three or more outcomes, use else if — or the switch statement from the next lecture. Dart also has switch expressions, which choose between many values neatly; we will study them in Lecture 025 — Modern Switch Expressions.


13. A Real-World Example

A shop gives a discount based on the order total, and free delivery for members:

dart
void main() {
  var total = 6500;
  var isMember = true;

  final int discount;
  if (total >= 10000) {
    discount = 15;
  } else if (total >= 5000) {
    discount = 10;
  } else if (total >= 2000) {
    discount = 5;
  } else {
    discount = 0;
  }

  var finalTotal = total - total * discount ~/ 100;
  var delivery = isMember ? 0 : 250;

  print('Discount: $discount%');
  print('To pay: ${finalTotal + delivery}');
  print('Delivery: ${delivery == 0 ? 'free' : '$delivery'}');
}
output
Discount: 10%
To pay: 5850
Delivery: free

An else-if chain, ordered from the highest total down, assigns a final discount on every path. Two short two-way choices use ? :. Each tool does the job it is best at.


Code Examples

Example 1 — Even or Odd

dart
void main() {
  var number = 7;
  if (number % 2 == 0) {
    print('$number is even');
  } else {
    print('$number is odd');
  }
}
output
7 is odd

Example 2 — Positive, Negative, or Zero

dart
void main() {
  var number = -4;
  if (number > 0) {
    print('Positive');
  } else if (number < 0) {
    print('Negative');
  } else {
    print('Zero');
  }
}
output
Negative

Example 3 — Larger of Two Numbers

dart
void main() {
  var a = 18;
  var b = 25;
  var larger = a > b ? a : b;
  print('Larger: $larger');
}
output
Larger: 25

Example 4 — Time of Day

dart
void main() {
  var hour = 15;
  if (hour < 12) {
    print('Good morning');
  } else if (hour < 18) {
    print('Good afternoon');
  } else {
    print('Good evening');
  }
}
output
Good afternoon

Example 5 — Nested Check

dart
void main() {
  var username = 'sara';
  var password = '1234';
  if (username == 'sara') {
    if (password == 'secret') {
      print('Logged in');
    } else {
      print('Wrong password');
    }
  } else {
    print('Unknown user');
  }
}
output
Wrong password

Example 6 — Reading Input Safely

dart
void main() {
  var input = 'abc';
  var age = int.tryParse(input);
  if (age == null) {
    print('"$input" is not a number.');
  } else {
    print('Next year you will be ${age + 1}.');
  }
}
output
"abc" is not a number.

In the else branch, age is promoted from int? to int.

Example 7 — Student Report

dart
void main() {
  var name = 'Ali';
  var mark = 86;

  final String grade;
  if (mark >= 80) {
    grade = 'A';
  } else if (mark >= 60) {
    grade = 'B';
  } else if (mark >= 50) {
    grade = 'C';
  } else {
    grade = 'F';
  }

  print('$name: $mark (${grade == 'F' ? 'failed' : 'passed'}, grade $grade)');
}
output
Ali: 86 (passed, grade A)

Example 8 — Shopping Total with Shipping

dart
void main() {
  var price = 1200;
  var quantity = 2;
  var subtotal = price * quantity;

  var shipping = subtotal >= 2000 ? 0 : 200;
  print('Subtotal: $subtotal');
  print('Shipping: $shipping');
  print('Total: ${subtotal + shipping}');
}
output
Subtotal: 2400
Shipping: 0
Total: 2400

Example 9 — Bank Withdrawal

dart
void main() {
  var balance = 1000;
  var amount = 1200;

  if (amount <= 0) {
    print('Enter a positive amount.');
  } else if (amount > balance) {
    print('Insufficient funds. Balance: $balance');
  } else {
    balance -= amount;
    print('Withdrew $amount. Balance: $balance');
  }
}
output
Insufficient funds. Balance: 1000

The invalid amount is rejected first, so later branches can assume it is positive. Only the last branch changes balance.

Example 10 — Temperature Advice

dart
void main() {
  var celsius = 31.5;
  String advice;
  if (celsius >= 30) {
    advice = 'Stay hydrated.';
  } else if (celsius >= 15) {
    advice = 'Enjoy the weather.';
  } else {
    advice = 'Take a jacket.';
  }
  print('$celsius°C — $advice');
}
output
31.5°C — Stay hydrated.

Common Beginner Mistakes

1. Giving else a condition — } else (mark < 50) {

output
Error: Expected ')' before this.

else never has a condition. Use else if (...) when you need one.

2. Conditions in the wrong order

if (mark >= 50) before else if (mark >= 80) gives every high mark a C (section 4). No error — just wrong answers. Put the narrowest condition first.

3. A semicolon after the condition

dart
void main() {
  var mark = 40;
  if (mark >= 50); {
    print('Pass');
  }
}
output
Pass

The ; ends the if with an empty statement, so the block below runs always. dart analyze warns Unnecessary empty statement., and dart format moves the ; onto its own line, where the bug is easy to see.

4. Leaving a path without a value (section 8)

output
Error: Non-nullable variable 'grade' must be assigned before it can be used.

Add a final else so every path assigns the variable.

5. Declaring the variable inside the branches

dart
void main() {
  var mark = 72;
  if (mark >= 50) {
    var result = 'Pass';
  } else {
    var result = 'Fail';
  }
  print(result); // ✗
}
output
Error: Undefined name 'result'.
  print(result); // ✗
        ^^^^^^

A variable declared inside a { } block exists only inside that block. Declare it before the if, then assign it in each branch.

6. Using ? : to run actions

mark >= 50 ? print('Pass') : print('Fail'); runs, but hides two actions inside an expression. Write if-else.


Best Practices

  • Use if-else for two outcomes, not two opposite ifs.
  • Order an else-if chain from the narrowest condition to the widest.
  • End a chain with else when every case needs an answer.
  • Always use braces { }, even for one-line branches.
  • Prefer a flat else-if chain over deep nesting.
  • Declare the variable before the if and assign it in every branch — final if possible.
  • Use ? : for a short choice between two values; never chain more than one ?.

Mini Challenge

Sara's phone shows a battery message. Store battery = 15 and isCharging = false. If the phone is charging, print Charging.... Otherwise print Battery low! below 20, Battery OK below 80, and Battery full from 80 up. On a second line, print Level: 15%.

output
Battery low!
Level: 15%

Try it yourself before opening the solution.

Show solution
dart
void main() {
  var battery = 15;
  var isCharging = false;

  if (isCharging) {
    print('Charging...');
  } else if (battery < 20) {
    print('Battery low!');
  } else if (battery < 80) {
    print('Battery OK');
  } else {
    print('Battery full');
  }
  print('Level: $battery%');
}
output
Battery low!
Level: 15%

Charging is checked first, because it overrides every level message.


Practice Questions

Work through these in order — they run from beginner to application to challenge.

Beginner

  1. Store age = 16. Print Can vote if age is at least 18, otherwise Too young.
  2. Store number = 0. Print Positive, Negative, or Zero using an else-if chain.
  3. Rewrite this if-else as a single line with ? :, storing the result in status, then print it: if (isOpen) { status = 'Open'; } else { status = 'Closed'; } with isOpen = false.

Application

  1. Store mark = 55. Print the grade: A from 80, B from 60, C from 50, otherwise F.
  2. Store price = 900 and balance = 750. If the balance covers the price, subtract it and print Bought! Balance: …; otherwise print Short by ….
  3. Store celsius = -3. Using ? : inside the interpolation, print -3°C: below freezing (or above freezing from 0 up).
  4. Store var input = ''; and String? name = input.isEmpty ? null : input;. If name is null, print Hello, guest!; otherwise print the name and its length as Hello, Ali (3 letters).
  5. Store items = 3. Print You have 3 items. — but item instead of items when the count is 1. Use ? : inside the interpolation.

Challenge

  1. This program prints the wrong grade for mark = 92. Find the bug and fix it:

    dart
    if (mark >= 60) {
      print('B');
    } else if (mark >= 90) {
      print('A');
    } else {
      print('C');
    }
  2. A cinema ticket costs 800. Children under 12 pay half, people 60 and over pay 500, and students (any age from 12 to 59) pay 600. Store age = 21 and isStudent = true, assign the price to a final int in an else-if chain, and print Ticket: 600.


Practice Answers

Question 1 — Solution

dart
void main() {
  var age = 16;
  if (age >= 18) {
    print('Can vote');
  } else {
    print('Too young');
  }
}
output
Too young

Question 2 — Solution

dart
void main() {
  var number = 0;
  if (number > 0) {
    print('Positive');
  } else if (number < 0) {
    print('Negative');
  } else {
    print('Zero');
  }
}
output
Zero

Question 3 — Solution

dart
void main() {
  var isOpen = false;
  var status = isOpen ? 'Open' : 'Closed';
  print(status);
}
output
Closed

Question 4 — Solution

dart
void main() {
  var mark = 55;
  if (mark >= 80) {
    print('A');
  } else if (mark >= 60) {
    print('B');
  } else if (mark >= 50) {
    print('C');
  } else {
    print('F');
  }
}
output
C

Question 5 — Solution

dart
void main() {
  var price = 900;
  var balance = 750;
  if (balance >= price) {
    balance -= price;
    print('Bought! Balance: $balance');
  } else {
    print('Short by ${price - balance}');
  }
}
output
Short by 150

Question 6 — Solution

dart
void main() {
  var celsius = -3;
  print('$celsius°C: ${celsius < 0 ? 'below' : 'above'} freezing');
}
output
-3°C: below freezing

Question 7 — Solution

dart
void main() {
  var input = '';
  String? name = input.isEmpty ? null : input;
  if (name == null) {
    print('Hello, guest!');
  } else {
    print('Hello, $name (${name.length} letters)');
  }
}
output
Hello, guest!

With input = 'Ali' the else branch runs and prints Hello, Ali (3 letters); name.length is allowed there because of promotion.

Question 8 — Solution

dart
void main() {
  var items = 3;
  print('You have $items ${items == 1 ? 'item' : 'items'}.');
}
output
You have 3 items.

Question 9 — Solution

dart
void main() {
  var mark = 92;
  if (mark >= 90) {
    print('A');
  } else if (mark >= 60) {
    print('B');
  } else {
    print('C');
  }
}
output
A

92 >= 60 was true, so the old chain stopped at B. The narrower >= 90 must come first.

Question 10 — Solution

dart
void main() {
  var age = 21;
  var isStudent = true;

  final int price;
  if (age < 12) {
    price = 400;
  } else if (age >= 60) {
    price = 500;
  } else if (isStudent) {
    price = 600;
  } else {
    price = 800;
  }
  print('Ticket: $price');
}
output
Ticket: 600

Reaching else if (isStudent) already means the age is 12–59, so no range check is needed.


Quick Revision

  1. How many blocks of an if-else run?
  2. Why can else never have a condition?
  3. In an else-if chain, which branch runs when several conditions are true?
  4. What happens when no condition is true and there is no final else?
  5. Why may a final variable be assigned in both branches of an if-else?
  6. After if (x == null) { ... }, what does Dart know about x in the else branch?
  7. What is the difference between if-else and ? :?
  8. What does a semicolon right after if (...) do?

Key Takeaways

  • if-else runs exactly one of two blocks; else means "in every other case" and has no condition.
  • An else-if chain checks conditions top to bottom, and the first true one wins.
  • Order overlapping conditions from narrowest to widest — the wrong order is a silent bug.
  • The final else is optional; without it, possibly no branch runs.
  • A variable — even a final one — can be assigned in every branch, and Dart checks that no path is left out.
  • After if (x == null), the else branch treats x as non-nullable.
  • ? : chooses a value; if-else chooses actions. Use ? : for short two-way choices and else if for three or more.

What's Next?

Lecture 024 — switch Statements. An else-if chain can compare one value against many possibilities, but it repeats the variable in every condition: day == 'Mon', day == 'Tue', … A switch statement names the value once and lists the cases beneath it — cleaner when one value decides between many fixed options.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.