tezvyn:

Explain Dart switch exhaustiveness for enums versus sealed classes

AI-drafted, machine-checkedSource: dart.devadvanced

This tests Dart 3 exhaustiveness. A strong answer notes that enums and sealed classes both require exhaustive switches, but sealed classes allow distinct payloads because subclasses stay in the same library. A red flag is calling them just enums with methods.

WHAT THIS TESTS: Whether you understand Dart 3 compile-time exhaustiveness checking and how library-closed hierarchies enable safer pattern matching than flat enums. The interviewer wants to see that you know when to model state with a sealed class versus an enum.

A GOOD ANSWER COVERS: First, explain that Dart 3 switch statements and expressions are exhaustiveness-checked when the matched type is a finite set of known variants. Second, describe standard enums as a closed set of named constants; the compiler can verify exhaustiveness because the enum declaration lists every possible value and no new values can be added outside the declaring library. Third, describe sealed classes as a class modifier introduced in Dart 3.0 that restricts all direct subclasses to the same library; because the compiler sees the entire hierarchy, it can also prove exhaustiveness when you switch over every subtype. Fourth, contrast the two by stating that enum members share the same shape and cannot hold different data per member unless you add fields to every member, while each sealed subclass can define its own constructor parameters, fields, and methods, giving you algebraic data types. Fifth, mention the practical advantage: sealed classes let you build typed state machines where each state carries relevant payload, such as a loading state with a progress integer and an error state with a stack trace, all while keeping compile-time safety.

COMMON WRONG ANSWERS: Saying that sealed classes are exhaustively checked automatically without mentioning the same-library constraint. Claiming that you can add a new sealed subclass in another file or package and still get exhaustiveness. Stating that enums in Dart can carry different payloads per member natively. Asserting that exhaustiveness checking is a runtime feature rather than a compile-time static analysis guarantee. Treating sealed classes as merely a performance optimization or syntactic sugar over abstract classes.

LIKELY FOLLOW-UPS: How would you refactor a large switch on a sealed class when a new subtype is added? Can you combine sealed classes with mixins or interfaces and still preserve exhaustiveness? What happens if you use a wildcard default case instead of listing every subtype? How do records and patterns interact with sealed class destructuring in modern Dart?

ONE CONCRETE EXAMPLE: Imagine a network request result. With an enum you might define RequestState idle, loading, success, and error, but every state has the same structure, so you end up storing optional fields alongside the enum. With a sealed class, you write sealed class Result, then final class Success extends Result with a String data field, final class Error extends Result with an Exception error field, and final class Loading extends Result. A switch on Result r forces you to handle Success, Error, and Loading, and in the Success branch the compiler knows r.data is available. If you later add final class Cancelled extends Result in the same library, every switch immediately becomes a compile error until you handle the new case.

Read the original → dart.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.