Enums

By Syncfusion®, Inc. · Last updated

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

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.

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?

String or enum?

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

Accessing Enum Values

MemberGivesFor House.green
House.valuesa list of all values, in order[House.red, House.blue, House.green, House.yellow]
.namethe value's name as a String'green'
.indexits position, starting at 02
House.values.byName('green')the value with that nameHouse.green

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

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?

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):

What happens today?

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:

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

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:

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()

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

MistakeWrong ideaCorrect ideaWhat goes wrong
var h = blue;Values stand aloneWrite House.blueUndefined name 'blue'.
Storing choices as StringsText is simplerAn enum stops typos'Bleu' silently breaks your code.
byName('Blue')Case does not matterNames are exactAn invalid argument error.
A non-final field in an enumEnum values can changeEvery enum field must be finalA compile error.
A constructor without constAny constructor worksEnum constructors must be constA compile error.
Forgetting a case in a switchMissing values are skippedDart wants every value coveredAn exhaustiveness error.
Expecting index to start at 1The first value is 1index starts at 0Off-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.