# Class Modifiers

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Object-Oriented Programming
Source: https://www.devtutorials.ai/learn/dart/object-oriented/class-modifiers

> How abstract, base, interface, final, sealed and mixin class control who can make, extend or implement a class, and how sealed classes make switch check every case.

## What Are Class Modifiers?

**Class modifier** = a word in front of `class` that sets **rules** for how **other files** may use the class.

- Can they **make objects** of it?
- Can they **extend** it (be its child)?
- Can they **implement** it (sign its contract)?
- Inside the **same file (library)**, every rule is relaxed. The rules protect your class from **outside** code.

**Simple lesson:** a class modifier is a sign on the door: "who may come in, and how".

### A Real-World Example

Rooms in a school have different rules.

- The **library** is open to all: anyone may enter and borrow. That is a plain `class`.
- The **science lab** may be used only by following the lab's own steps. That is like `base`.
- The **exam paper store** is locked. Nobody outside may change anything. That is `final`.
- The **list of houses** is fixed: Red, Blue, Green, Yellow. Nobody adds a fifth. That is `sealed`.

Pick a modifier and see what other files are allowed to do:

Every **Run** box on this page is **one file**, so the outside-file errors cannot happen there.

When a rule only shows up across two files, this page shows the code in a plain box, with Dart's error message.

## What You Will Learn

In this lesson, you will learn:

1. The modifiers `abstract`, `base`, `interface` and `final`.
2. The `sealed` modifier, and why `switch` loves it.
3. Combined modifiers: `abstract interface` and `mixin class`.
4. One table that compares them all.
5. How to choose the right modifier.

## abstract, base, interface and final

You met `abstract` in **Polymorphism**. Three more modifiers control the other doors.

### base

**`base class`** = other files may **extend** it, but may **not implement** it.

- Why? Every child then really runs the parent's code. Nobody can fake it with `implements`.
- Children of a `base` class must themselves be `base`, `final` or `sealed`.

```dart runnable title="A base class and its child"
base class Account {
  int _balance = 0;
  int get balance => _balance;

  void deposit(int rupees) {
    if (rupees > 0) {
      _balance += rupees;
    }
  }
}

base class SavingsAccount extends Account {
  void addInterest() => deposit(balance ~/ 10);
}

void main() {
  var acc = SavingsAccount();
  acc.deposit(500);
  acc.addInterest();
  print(acc.balance);
}
```

In another file, `class FakeAccount implements Account {}` gives: `The class 'Account' can't be implemented outside of its library because it's a base class.`

### interface

**`interface class`** = other files may **implement** it, but may **not extend** it.

- Use it for a pure contract that others fill in.
- Nobody can inherit and quietly change half of your code.

```dart
// printer.dart
interface class Printer {
  void printPage(String text) => print(text);
}

// main.dart
class LaserPrinter extends Printer {}   // Error: can't be extended outside of its library
class InkPrinter implements Printer {   // OK
  @override
  void printPage(String text) => print('ink: $text');
}
```

Inside the **same** file, both are allowed, so the Run box can show a working implementation:

```dart runnable title="Implementing an interface class"
interface class Printer {
  void printPage(String text) => print(text);
}

class InkPrinter implements Printer {
  @override
  void printPage(String text) => print('ink: $text');
}

void main() {
  Printer p = InkPrinter();
  p.printPage('Class 7A timetable');
}
```

### final

**`final class`** = other files may **not extend** and may **not implement** it. They can only **use** it.

- Use it when the class must stay exactly as you wrote it.
- You can still change its insides later, without breaking anyone's child class.

```dart runnable title="A final class can still be used"
final class ExamTimer {
  final int minutes;
  ExamTimer(this.minutes);

  String get label => '$minutes minutes left';
}

void main() {
  var t = ExamTimer(90);
  print(t.label);
}
```

**Simple lesson:** `base` allows only children, `interface` allows only contracts, and `final` allows neither.

## sealed

**`sealed class`** = a class with a **fixed, known** list of children, all in the **same file**.

- A sealed class is also **abstract**. You cannot make objects of it.
- No other file can add a new child.
- So Dart **knows every child**. A `switch` can check you handled them all.

### Sealed Classes and Exhaustive switch

**Exhaustive switch** = a switch that covers **every possible** case. (You met this with enums in **Enums**.)

```dart runnable title="Every kind of result is handled"
sealed class ExamResult {}

class Pass extends ExamResult {
  final int marks;
  Pass(this.marks);
}

class Fail extends ExamResult {
  final int marks;
  Fail(this.marks);
}

class Absent extends ExamResult {}

String message(ExamResult r) => switch (r) {
  Pass(marks: var m) => 'Passed with $m',
  Fail(marks: var m) => 'Failed with $m. Try again!',
  Absent() => 'Was absent',
};

void main() {
  var results = [Pass(82), Fail(28), Absent()];
  for (var r in results) {
    print(message(r));
  }
}
```

- There is no `_` (default) arm, and none is needed.
- `Pass(marks: var m)` checks the type **and** takes out the marks. You will learn this fully in **Pattern Matching**.

### Forgetting a Case

Now imagine someone adds `class Withheld extends ExamResult {}` to the same file:

```dart
String message(ExamResult r) => switch (r) {
  Pass(marks: var m) => 'Passed with $m',
  Fail(marks: var m) => 'Failed with $m. Try again!',
  Absent() => 'Was absent',
};
// Error: The type 'ExamResult' is not exhaustively matched by the switch cases
// since it doesn't match 'Withheld()'.
```

Real Dart finds the forgotten case **before** the program runs. That is the reason to use `sealed`.

The course runner does not check exhaustiveness. It reports a missing case only when it actually happens while running.

Real Dart (and your editor) check it before running, so you see the problem at once.

**Simple lesson:** `sealed` fixes the list of children, so `switch` can make sure none is forgotten.

## Combined Modifiers

| Combination | Meaning |
|---|---|
| `abstract interface class` | A pure contract: no objects, and others may only implement it. |
| `abstract base class` | A plan that others must extend, never fake with `implements`. |
| `abstract final class` | No objects and no children outside: a box for `static` helpers. |
| `mixin class` | A class that can also be used after `with`. (See **Mixins**.) |

```dart runnable title="abstract final class as a box of helpers"
abstract final class Grades {
  static String of(int marks) {
    if (marks >= 90) return 'A';
    if (marks >= 75) return 'B';
    if (marks >= 50) return 'C';
    return 'D';
  }
}

void main() {
  for (var m in [95, 80, 61, 40]) {
    print('$m -> ${Grades.of(m)}');
  }
}
```

**Simple lesson:** modifiers can be combined to say exactly what you mean.

## The Comparison Table

What code in **another file** may do:

| Modifier | Make objects? | Extend? | Implement? | Use for |
|---|---|---|---|---|
| (none) | yes | yes | yes | most classes |
| `abstract` | no | yes | yes | a plan with some shared code |
| `base` | yes | yes | no | code every child must really run |
| `interface` | yes | no | yes | a contract others fill in |
| `final` | yes | no | no | a class that must stay as written |
| `sealed` | no | no | no | a fixed family for `switch` |
| `abstract interface` | no | no | yes | a pure contract |
| `mixin class` | yes | yes | yes | a class that is also a mixin |

### Choosing a Modifier

- Start with **no modifier**. Add one only when you need a rule.
- A **fixed list of kinds** (results, shapes, messages)? Use **`sealed`**.
- A **contract** only? Use **`abstract interface`**.
- Must stay **unchanged** for others? Use **`final`**.

**Easy way to remember**

- `base` = "**base** your class on mine, do not fake it".
- `interface` = "only **implement** me".
- `final` = "**finished**: use me, do not build on me".
- `sealed` = "the family is **sealed**: no new children".

**Simple lesson:** pick the smallest rule that protects your class.

## TL;DR

1. **Class modifiers** set rules for **other files**: make, extend, implement.
2. **`base`**: extend only. **`interface`**: implement only. **`final`**: neither.
3. **`sealed`**: a fixed family in one file, abstract, and checked by `switch`.
4. **Combined:** `abstract interface`, `abstract final`, `mixin class`.
5. Inside the **same file**, the rules do not apply.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Expecting rules inside one file | Modifiers work everywhere | They limit **other** files | No error appears in your test file. |
| `var r = ExamResult();` for a sealed class | Sealed classes make objects | Sealed classes are abstract | A compile error. |
| Children of a sealed class in another file | Any file can add one | All children live in the same file | A compile error. |
| A plain child of a `base` class | Children can be plain | Children must be `base`, `final` or `sealed` | A compile error. |
| Adding a `_` arm to every sealed switch | A default is always safer | Without `_`, Dart warns you about new children | New cases are silently missed. |
| Using `final class` for everything | Locking is always good | Lock only what needs protecting | Other code cannot build on yours. |

## Check Yourself

## Exercises

## What to Remember

- Class modifiers set rules for other files: make objects, extend, implement.
- `base` allows extending only, `interface` allows implementing only, `final` allows neither.
- `sealed` gives a fixed family in one file, and `switch` can check every child.
- `abstract interface`, `abstract final` and `mixin class` combine the rules.
- Start with no modifier, and add the smallest rule you need.

Next: **Generics**. You will write one class or function that works safely with many types.
