# Enums

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

> How to make a fixed set of choices with enums, read their name and index, add fields and methods with enhanced enums, and use enums in switch.

## What Are Enums?

**Enum (enumeration)** = a type with a **fixed list** of named values. Nothing else is allowed.

For example:

- the days of the week: `monday`, `tuesday` ... `sunday`
- the school houses: `red`, `blue`, `green`, `yellow`
- the result of an exam: `pass`, `fail`, `absent`

**Simple lesson:** an enum is a closed list of choices, and Dart will not accept anything outside it.

### A Real-World Example

Every student belongs to one house.

- If the house is stored as text, someone may type `'Bleu'` or `'blue '` by mistake.
- Then the "Blue House" score board misses that student.
- With an enum, the only choices are `House.red`, `House.blue`, `House.green` and `House.yellow`. A typo does not compile.

Click a house to see what an enum value knows about itself:

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

An enum value prints as `EnumName.value`, like `House.blue`.

## What You Will Learn

In this lesson, you will learn:

1. What enums are, and how to create them.
2. How to use `values`, `name`, `index` and `byName()`.
3. Enhanced enums with fields, constructors and methods.
4. How to give an enum its own `toString()`.
5. How to compare enums and use them in `switch`.

## Enum Fundamentals

### Creating Enums

```text
enum EnumName { value1, value2, value3 }
```

- The name uses **UpperCamelCase**: `House`, `Day`, `ExamResult`.
- The values use **lowerCamelCase**: `red`, `monday`, `notStarted`.
- An enum goes **outside** `main()`, like a class.

```dart runnable title="Your first enum"
enum House { red, blue, green, yellow }

void main() {
  var myHouse = House.blue;
  print(myHouse);
  print(myHouse == House.blue);
  print(myHouse == House.red);
}
```

### Enum Values

- **Enum value** = one of the fixed choices, like `House.blue`.
- You always write the enum name first: `House.blue`, not `blue`.
- Every enum value is an **object** (see **Classes**), made once and shared.

### Why Not Just Use Strings?

**Simple lesson:** an enum turns a set of allowed words into a real type that Dart can check.

## Accessing Enum Values

| Member | Gives | For `House.green` |
|---|---|---|
| `House.values` | a list of all values, in order | `[House.red, House.blue, House.green, House.yellow]` |
| `.name` | the value's name as a String | `'green'` |
| `.index` | its position, starting at 0 | `2` |
| `House.values.byName('green')` | the value with that name | `House.green` |

```dart runnable title="values, name, index and byName"
enum House { red, blue, green, yellow }

void main() {
  print(House.values);
  print(House.green.name);
  print(House.green.index);
  print(House.values.length);
  var chosen = House.values.byName('yellow');
  print(chosen);
  for (var h in House.values) {
    print('${h.index}: ${h.name}');
  }
}
```

### byName with a Wrong Name

```dart runnable expect-error title="There is no purple house"
enum House { red, blue, green, yellow }

void main() {
  print(House.values.byName('purple'));
}
```

The error says there is **no enum value with that name**. `byName` is exact, so `'Green'` with a capital G also fails.

**Simple lesson:** `values` lists every choice, `name` gives its text, and `index` gives its position.

## Enum Comparisons

### Comparing Enum Values

- **`==`** checks if two values are the **same** choice.
- **`index`** lets you compare **order**: is Tuesday before Friday?

```dart runnable title="Comparing days"
enum Day { monday, tuesday, wednesday, thursday, friday, saturday, sunday }

void main() {
  var today = Day.tuesday;
  var testDay = Day.friday;
  print(today == Day.tuesday);
  print(today.index < testDay.index);
  print('Days until the test: ${testDay.index - today.index}');
  print(today == Day.saturday || today == Day.sunday);
}
```

### Using Enums in switch Statements

Enums and `switch` are a perfect match (see **Conditional Statements**):

**Exhaustive switch** = a switch that covers **every** value of the enum. Dart checks this for you:

- If you forget a case and have no `default`, real Dart reports an error before running.
- So when you add a new value to an enum later, Dart shows every switch you must update.

A switch expression works too:

```dart runnable title="A switch expression on an enum"
enum Result { pass, fail, absent }

void main() {
  var r = Result.absent;
  var message = switch (r) {
    Result.pass => 'Well done!',
    Result.fail => 'Try again next term.',
    Result.absent => 'Please see the class teacher.',
  };
  print(message);
}
```

No `_` arm is needed, because the three arms cover every Result value.

Do not save `index` in a file or database to remember a choice.

If someone adds a new value in the middle of the enum later, every index after it changes. Save `name` instead, and read it back with `byName`.

**Simple lesson:** use `==` to compare enum values, and `switch` to act on each one.

## Enhanced Enums

**Enhanced enum** = an enum that also has **fields**, a **constructor** and **methods**, like a small class.

### Enum Fields and Constructors

```dart runnable title="Houses with a motto and points"
enum House {
  red('Courage', 120),
  blue('Wisdom', 145),
  green('Growth', 98),
  yellow('Joy', 110);

  final String motto;
  final int points;

  const House(this.motto, this.points);
}

void main() {
  print(House.blue.motto);
  print(House.blue.points);
  for (var h in House.values) {
    print('${h.name}: ${h.motto}, ${h.points} points');
  }
}
```

Rules for enhanced enums:

- **Constant constructor:** the constructor must be `const`.
- **Read-only fields:** every field must be `final`. Enum values never change.
- **Parameterized enum values:** each value passes its own arguments: `red('Courage', 120)`.
- The value list ends with `;` before the fields.

### Enum Methods and Custom Properties

Methods can use the fields, just like in a class:

```dart runnable title="Methods on an enum"
enum Planet {
  mercury(3.7),
  earth(9.8),
  jupiter(24.8);

  final double gravity;
  const Planet(this.gravity);

  double weightOf(double massKg) => massKg * gravity;

  bool get isHeavierThanEarth => gravity > 9.8;
}

void main() {
  for (var p in Planet.values) {
    var w = p.weightOf(40.5).toStringAsFixed(1);
    print('${p.name}: $w N, heavier than Earth: ${p.isHeavierThanEarth}');
  }
}
```

`isHeavierThanEarth` is a **getter**: a method you read like a field, with no `()` (see **Encapsulation**).

### Overriding toString()

```dart runnable title="A friendlier print"
enum Subject {
  maths('Mathematics'),
  sci('Science'),
  eng('English');

  final String fullName;
  const Subject(this.fullName);

  @override
  String toString() => fullName;
}

void main() {
  print(Subject.sci);
  print('Favourite: ${Subject.maths}');
  print(Subject.eng.name);
}
```

`toString()` now prints the full name. `name` still gives the short value name, `eng`.

**Easy way to remember**

- A fixed list of choices: **enum**.
- Each choice needs extra data: **enhanced enum**, with `final` fields and a `const` constructor.
- Act on each choice: **switch**, and let Dart check you covered them all.

**Simple lesson:** an enhanced enum gives every choice its own data and behaviour.

## TL;DR

1. **Enum** = a fixed list of values: `enum House { red, blue, green }`.
   - Use as `House.red`. Each value is a shared object.
2. **Members:** `House.values`, `.name`, `.index`, `House.values.byName('red')`.
3. **Compare** with `==`, and order with `index`.
   - **switch** on enums, and Dart checks every value is covered.
4. **Enhanced enum** = values with arguments, `final` fields, a `const` constructor, and methods.
5. **`toString()`** can be overridden to print a friendlier text.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `var h = blue;` | Values stand alone | Write `House.blue` | `Undefined name 'blue'`. |
| Storing choices as Strings | Text is simpler | An enum stops typos | `'Bleu'` silently breaks your code. |
| `byName('Blue')` | Case does not matter | Names are exact | An invalid argument error. |
| A non-final field in an enum | Enum values can change | Every enum field must be `final` | A compile error. |
| A constructor without `const` | Any constructor works | Enum constructors must be `const` | A compile error. |
| Forgetting a case in a switch | Missing values are skipped | Dart wants every value covered | An exhaustiveness error. |
| Expecting `index` to start at 1 | The first value is 1 | `index` starts at 0 | Off-by-one numbers. |

## Check Yourself

## Exercises

## What to Remember

- An enum is a fixed list of choices, used as `EnumName.value`.
- `values` lists them, `name` gives the text, and `index` gives the position from 0.
- Compare enum values with `==`, and use them in `switch`, where Dart checks every case.
- Enhanced enums add `final` fields, a `const` constructor and methods.
- Override `toString()` for friendlier output, while `name` stays the same.

Next: **Encapsulation**. You will learn to hide an object's data and control how it is read and changed.
