# Conditional Statements

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Control Flow
Source: https://www.devtutorials.ai/learn/dart/control-flow/conditional-statements

> How a program makes decisions with if, else, else if, nested conditions, switch statements and switch expressions.

## What Is a Conditional Statement?

**Conditional statement** = code that runs only when a condition is `true`.

**Condition** = a question with a `true` or `false` answer, like `marks >= 35`.

For example:

- **if** it rains, take an umbrella
- **if** marks are 35 or more, print "Pass", **else** print "Fail"
- **if** today is Sunday, the school is closed

Conditional statements let a program make **decisions**.

**Simple lesson:** a conditional statement asks a question, and runs different code for different answers.

### A Real-World Example

Your school's report card app gives a grade for every student.

- 90 or more is **Grade A**.
- 75 or more is **Grade B**.
- 35 or more is **Grade C**.
- Anything less is **Try again**.

The app runs the same code for every student, but each student can get a different grade. That is a decision chain, and you will build it in this lesson.

Every **Run** box on this page runs on the course's Dart runner in your browser.

Change the values and run again, to see a different path through the code.

## What You Will Learn

In this lesson, you will learn:

1. How conditions work, with `&&`, `||` and `!`.
2. The `if`, `if else` and `else if` statements.
3. Nested conditions.
4. `switch` statements and `switch` expressions.
5. When to use each kind of decision.

## Conditional Fundamentals

### Evaluating Conditions

Every condition becomes `true` or `false`. Dart works it out using the operators from **Operators**.

- **Single condition:** `marks >= 35`
- **Both must be true (`&&`):** `age >= 18 && hasVoterId`
- **At least one (`||`):** `isSunday || isHoliday`
- **The opposite (`!`):** `!isAbsent`

```dart runnable title="Conditions become true or false"
void main() {
  var marks = 82;
  var isSunday = false;
  var isHoliday = true;
  var isAbsent = false;

  print(marks >= 35);
  print(marks >= 35 && marks < 90);
  print(isSunday || isHoliday);
  print(!isAbsent);
}
```

### Using Conditions Effectively

- **Name `bool` variables like questions:** `isHoliday`, `hasPaidFees`.
- **Write `if (isHoliday)`,** not `if (isHoliday == true)`.
- **Store a long condition in a variable** first, to make it easy to read.

**Simple lesson:** every decision starts with a condition that is either `true` or `false`.

## if Statement

**`if`** = run a block only when the condition is `true`.

```text
if (condition) {
  // runs only when condition is true
}
```

```dart runnable title="A hot day warning"
void main() {
  var temperature = 38;
  if (temperature > 35) {
    print('It is very hot. Drink water!');
  }
  print('Have a good day.');
}
```

- The condition goes inside `( )`.
- The code to run goes inside `{ }`.
- When the condition is `false`, Dart skips the block and carries on.

Change `38` to `30` and run again. Only the last line prints.

**Simple lesson:** `if` runs a block only when its condition is `true`.

## if else Statement

**`if else`** = one block when the condition is `true`, another block when it is `false`.

```dart runnable title="Pass or fail"
void main() {
  var marks = 28;
  if (marks >= 35) {
    print('Pass');
  } else {
    print('Fail. Better luck next time!');
  }
}
```

**Alternative execution path** = a second way through the code. `else` gives exactly one.

### Combining Multiple Conditions

```dart runnable title="Can this person vote?"
void main() {
  var age = 19;
  var hasVoterId = true;
  if (age >= 18 && hasVoterId) {
    print('You can vote.');
  } else {
    print('You cannot vote yet.');
  }
}
```

### if vs if else

- **`if` alone:** something extra may happen, or nothing happens.
- **`if else`:** exactly **one** of two things always happens.

**Simple lesson:** `if else` always runs one of its two blocks, never both and never none.

## else if Statement

**`else if`** = check another condition when the ones before it were `false`.

**Decision chain** = a chain of `if`, `else if` and `else` that picks **one** path.

Move the slider and watch which block runs:

Look at two things:

- **Dart checks from the top**, one condition at a time.
- **It stops at the first `true` one.** The rest are skipped, even if they are also true.

```dart runnable stdin="82" title="Grades from marks you type"
import 'dart:io';

void main() {
  print('Enter marks:');
  var marks = int.tryParse(stdin.readLineSync() ?? '') ?? 0;
  if (marks >= 90) {
    print('Grade A');
  } else if (marks >= 75) {
    print('Grade B');
  } else if (marks >= 35) {
    print('Grade C');
  } else {
    print('Try again');
  }
}
```

Change the **Input** to `95`, then `40`, then `10`.

### Condition Evaluation Order

The order matters. Here the checks are in the wrong order:

```dart runnable title="A bug: the conditions are in the wrong order"
void main() {
  var marks = 95;
  if (marks >= 35) {
    print('Grade C');
  } else if (marks >= 75) {
    print('Grade B');
  } else if (marks >= 90) {
    print('Grade A');
  }
}
```

A score of 95 gets Grade C, because `95 >= 35` is checked first and is `true`.

**Fix:** put the **strictest** condition first.

Never put a `;` right after `if (...)`.

`if (marks >= 35);` ends the if statement there. The block after it then runs every time, whatever the marks.

**Simple lesson:** an `else if` chain runs only the first true block, so order the checks from strictest to loosest.

## Nested Conditions

**Nested condition** = an `if` inside another `if`.

Use it when a second question only makes sense after the first answer.

### Multi-Level Decision Making

- **Outer `if`:** the first and most important check.
- **Inner `if`:** only asked when the outer check passed.
- **Keep it shallow.** More than two levels is hard to read. Use `&&` or `else if` instead where you can.

**Simple lesson:** nest an `if` only when the inner question depends on the outer answer.

## Switch Statements

**`switch`** = compare one value against a list of possible values, and run the matching case.

```dart runnable title="What happens on each day?"
void main() {
  var day = 'Wednesday';
  switch (day) {
    case 'Monday':
      print('Maths test');
    case 'Wednesday':
      print('Sports period');
    case 'Friday':
      print('Library visit');
    default:
      print('Regular classes');
  }
}
```

### The Parts of a switch

- **`switch (day)`** = the value to check.
- **`case 'Monday':`** = a **case label**. If `day` equals `'Monday'`, its code runs.
- **`default:`** = runs when no case matches. It is like a final `else`.

### Multiple Cases

Write cases one after another, with no code between them, to share one block:

```dart runnable title="Two days share one block"
void main() {
  var day = 'Sunday';
  switch (day) {
    case 'Saturday':
    case 'Sunday':
      print('Holiday!');
    default:
      print('School day');
  }
}
```

### The break Statement

- In Dart 3, a case **stops by itself** when its code ends. You do not need `break`.
- You may still see `break;` at the end of a case in older code. It does the same thing.
- In many other languages, forgetting `break` runs the next case too. Dart does not do that.

**Simple lesson:** `switch` picks the matching `case`, and `default` handles everything else.

## Switch Expressions

**Switch expression** = a `switch` that **gives back a value**, written with `=>`.

```dart runnable title="A grade with a switch expression"
void main() {
  var marks = 78;
  var grade = switch (marks) {
    >= 90 => 'A',
    >= 75 => 'B',
    >= 35 => 'C',
    _ => 'Try again',
  };
  print('Grade: $grade');
}
```

- Each line is an **arm**: `pattern => value`.
- **`_`** = matches anything. It is like `default`.
- Arms are separated by commas, and the whole switch ends with `;`.

### Pattern Matching in Switch

**Pattern** = a shape that a value is tested against.

- `>= 90` is a **relational pattern**: "is the value at least 90?"
- `'Saturday' || 'Sunday'` matches either value.
- `_` is a **wildcard pattern**: it matches anything.

```dart runnable title="Patterns with ||"
void main() {
  var day = 'Saturday';
  var type = switch (day) {
    'Saturday' || 'Sunday' => 'Weekend',
    _ => 'Weekday',
  };
  print(type);
}
```

You will learn many more patterns in **Pattern Matching**.

### When to Use switch

- **One value, many exact choices:** a day, a menu option, a grade letter. Use `switch`.
- **Ranges or different variables:** `marks >= 75`, `age && hasId`. Use `if` or a switch expression with patterns.
- **You need a value back:** use a switch expression.

**Simple lesson:** a switch expression turns a value into another value, arm by arm.

## Conditional Expressions

**Conditional expression** = a short decision that **gives a value**, on one line.

You already know two of them:

- **`?:`** (from **Operators**) picks one of two values.
- **`??`** (from **Null Safety**) gives a default when a value is null.

```dart runnable title="One-line decisions"
void main() {
  var marks = 64;
  var result = marks >= 35 ? 'Pass' : 'Fail';
  print(result);

  String? nickname;
  var callName = nickname ?? 'Student';
  print('Hello, $callName');
}
```

### When to Use Conditional Expressions

- **Use them** for a simple choice between two values.
- **Use `if else`** when each path does several things.
- **Use a switch expression** when there are more than two choices.

**Easy way to remember**

- Two paths that **do** things: `if else`.
- Many exact values: `switch`.
- Need a **value** back: `?:` for two choices, a switch expression for more.

**Simple lesson:** use `?:` and `??` for short value choices, and `if` for actions.

## TL;DR

1. **Condition** = a `true` or `false` question. Join them with `&&`, `||` and `!`.
2. **`if`** = run when true. **`if else`** = one of two blocks.
3. **`else if` chain** = runs the first true block only.
   - Put the strictest check first.
4. **`switch`** = match one value against cases. `default` catches the rest.
   - No `break` needed in Dart 3.
5. **Switch expression** = `switch (x) { p => v, _ => w }` gives a value.
   - **`?:`** and **`??`** = one-line value choices.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `if (marks = 35)` | `=` compares | Use `==` to compare | An error. |
| Loose check first | Dart checks every condition | Dart stops at the first true one | Everyone gets the same low grade. |
| `;` after `if (...)` | It is just style | `if (x);` ends the if right there | The block always runs. |
| Missing braces | Indentation decides the block | Only `{ }` decides the block | The wrong lines run. |
| `if (isHoliday == true)` | You must compare with true | `if (isHoliday)` is enough | Longer code, same result. |
| No `_` in a switch expression | Some arm will match | Cover every value, often with `_` | A "no case matched" error. |
| Deep nesting | More levels are clearer | Use `&&` or `else if` | Code nobody can follow. |

## Check Yourself

## Exercises

## What to Remember

- `if` runs a block when its condition is true. `else` gives a second path.
- An `else if` chain runs only the first true block, so put the strictest check first.
- Nest an `if` only when the inner question depends on the outer one.
- `switch` matches one value against cases. In Dart 3 it needs no `break`.
- A switch expression gives back a value, with `_` matching everything else.

Next: **Loops**. You will learn how to repeat code without writing it again and again.
