Dart 3.0 introduced class modifiers, and at first glance, the combinations can feel overwhelming. base, final, interface, mixin. How do they all fit together? What combinations are valid? Which ones are redundant?

It turns out there’s an elegant way to understand the entire system: lattice theory.

The Four Capabilities

Every Dart type has some combination of four fundamental capabilities:

  1. Extendable: can be used with extends
  2. Implementable: can be used with implements
  3. Mixinable: can be used with with
  4. Constructable: can be instantiated directly

Each class modifier combination enables or restricts these capabilities. The lattice below shows how all valid combinations relate to each other.

The Class Modifiers Lattice

Dart Class Modifiers Lattice

Reading the Lattice

The lattice flows from bottom to top:

  • Bottom: Nothing (no capabilities)
  • Top: mixin class (all four capabilities)

Each arrow represents adding one capability. Follow arrows upward to see how adding capabilities transforms one modifier combination into another.

Color Coding

Node backgrounds:

  • Yellow: Existed before Dart 3.0
  • Green: New with class modifiers
  • Red: Impossible combinations

Arrow colors represent which capability is being added:

  • Orange: Mixinable
  • Teal: Extendable
  • Blue: Implementable
  • Brown: Constructable

Key Insights

1. mixin class is Maximum Capability

A plain mixin class has all four capabilities. It’s the most permissive type you can declare. This is why it sits at the top of the lattice.

2. Some Combinations Are Impossible

Notice the red nodes. For example, final base mixin class is impossible because mixin classes must be extendable (that’s how mixins work), but final prevents extension.

3. Pre-Dart 3.0 Types Were Limited

The yellow nodes show what existed before: class, abstract class, and mixin. The green nodes are all the new combinations that class modifiers enable.

Practical Examples

// All four capabilities
mixin class A {}

// Remove implementability, must extend, can't just implement
base mixin class B {}

// Remove extendability and mixinability, can only implement
interface class C {}

// Remove everything except constructability
final class D {}

Why Lattices?

Lattices aren’t just a visualization trick. They reveal the algebraic structure of the type system. The fact that Dart’s class modifiers form a clean lattice means the design is internally consistent. There are no arbitrary restrictions or special cases.

Understanding this structure helps you:

  • Remember which combinations are valid
  • Predict what capabilities a type has
  • Choose the right modifier for your use case

The next time you’re unsure which class modifier to use, think about which capabilities you want to allow, and find the corresponding node in the lattice.

Conclusion

Complex systems with many interacting options are hard to reason about. When you have four independent boolean capabilities, you get 2^4 = 16 possible combinations. Trying to understand these combinations through documentation alone quickly becomes overwhelming.

Lattices provide a way to model these combinations visually and algebraically. Instead of memorizing rules, you can see the relationships. Each node is a valid state, each edge is a transition, and the structure itself encodes the constraints.

As a fun aside: this hierarchy is actually a 4-dimensional cube (a tesseract). Each of the four capabilities corresponds to one dimension, and moving along an edge means toggling that capability on or off. But since we can’t intuitively grasp 4-dimensional geometric objects (at least I can’t, though some claim they can), the lattice representation serves as a more accessible algebraic structure to aid intuition.


PS: To be complete when it comes to class modifiers, we would also have to discuss sealed classes. They don’t fit into this system. In my view, they are a separate feature and should be discussed separately.

PPS: Here’s the official documentation for class modifiers, the spec, and the officially maintained ANTLR grammar showing the syntax of modifiers.