skip to content

In Dart 3, what do `abstract interface class` and `abstract final class` declare, and which class modifier combinations does the compiler reject?

level: middleimportance: nice to knowfreq 25%

answer

  1. abstract, access, mixin, class
  2. pure interface idiom
  3. static-only namespace
  4. base, interface, final are exclusive
  5. no modifiers on enum

basics

~20 s

abstract interface class is Dart's pure interface: implementable elsewhere, never extended or constructed. abstract final class cannot be instantiated directly or subtyped outside its library, suiting static-only holders. Rejected: two of base/interface/final, sealed with any of them or abstract, and mixin with interface, final or sealed.

solid answer

~40 s

Modifiers stack in a fixed order: optional `abstract`, then at most one of `base`, `interface`, `final`, `sealed`, then optional `mixin`, then `class`. `abstract interface class PaymentGateway` is the idiomatic pure interface: other libraries may only `implements` it, and it may have abstract members. `abstract final class` cannot be instantiated directly anywhere nor subtyped outside its library, so it is used for holders of static members and constants; `dart:core` declares `String`, `int` and `double` as `abstract final`. The compiler rejects combinations that are contradictory or redundant: more than one of `base`/`interface`/`final`, `sealed` with `abstract` or with any of those three, and `mixin` with `interface`, `final` or `sealed`. `enum` and `extension type` accept no class modifiers.

go deeper

for a junior

Recall abstract interface class as Dart's pure interface and that sealed never combines with abstract.

for a middle

Explain the modifier order and why base, interface and final are mutually exclusive, and when abstract final class fits a static-only holder.

for a senior

Read unfamiliar declarations quickly in review and choose the least permissive combination that still supports the intended uses.

for a principal

Standardise modifier combinations across a codebase so contracts, closed types and constant holders are recognisable at a glance.

## The grammar of class modifiers A Dart 3 class declaration can carry several modifiers, but only in one order (dart.dev, "Combining modifiers"): 1. optional **`abstract`** — may have abstract members, cannot be constructed; 2. optional, **at most one** of **`base`**, **`interface`**, **`final`**, **`sealed`** — restrictions on other libraries; 3. optional **`mixin`** — can be mixed in; 4. the **`class`** keyword. Only `base` may precede a `mixin` declaration (`base mixin`). The modifiers do not apply to `enum`, `typedef`, `extension` or `extension type` declarations. ## `abstract interface class`: the pure interface Dart has no separate `interface` keyword for declaring contracts; every class exposes an implicit interface. Before Dart 3, a reader could not tell whether an abstract class was meant for extending or implementing. `abstract interface class` settles it: ```dart abstract interface class PaymentGateway { Future<void> charge(int cents); } ``` - other libraries may **implement** it; - they may **not extend** it, so they cannot inherit code from it; - nobody can **construct** it, because it is abstract. dart.dev calls this the most common use of `interface`. `dart:core` itself declares `List`, `Map`, `Comparable` and `Exception` as `abstract interface class`. ## `abstract final class`: closed and non-instantiable `abstract final class` cannot be instantiated directly anywhere (like any abstract class, it may still expose factory constructors), and it cannot be extended, implemented or mixed in outside its library. Two uses: - **A namespace for static members**, such as payment limits or currency constants, that nobody should instantiate or subtype: ```dart abstract final class PaymentLimits { static const int maxCents = 1000000; static const int minCents = 50; } ``` - **A closed type whose instances come only from the declaring library**, which is how `dart:core` declares `String`, `int`, `double` and `BigInt`: you can use them, but you cannot implement `String` yourself. ## Combinations the compiler rejects | Combination | Why it is invalid | |---|---| | two or more of `base`, `interface`, `final` | they control the same two capabilities, so they are mutually exclusive | | `sealed` with `abstract` | `sealed` is already implicitly abstract (analyzer: `abstract_sealed_class`) | | `sealed` with `base`, `interface` or `final` | `sealed` already blocks every outside subtyping, so they are redundant | | `mixin` with `interface`, `final` or `sealed` | those modifiers prevent mixing in, which `mixin` exists for | | any modifier on `enum` | enums are never extended, implemented or mixed in | | any modifier on `extension type` | extension types are only implemented by other extension types | ## Valid combinations worth knowing - `abstract base class` — can be extended, not implemented, not constructed. - `abstract interface class` — the pure interface above. - `abstract final class` — static holders and closed types. - `base mixin class`, `abstract mixin class`, `abstract base mixin class` — mixin classes with restrictions (mixins are covered in their own topic). - `sealed class` — alone; never with another access modifier. ## Reading declarations in an interview Interviewers often show a declaration and ask what outside code can do. Work left to right: 1. `abstract` or `sealed` present? Then no one can construct it. 2. Which access modifier? `base` keeps extend, `interface` keeps implement, `final` and `sealed` keep neither. 3. `mixin` present? Then it can also appear after `with`, unless `base` limits implementers. ## Version note All modifiers other than `abstract` need a library language version of 3.0 or later. Applying them to a published API is a breaking change and calls for a major version.

  • In Dart 3, how does an abstract final class differ from a class with only a private constructor for holding constants?
    A private constructor stops outside construction but still lets other libraries `implements` the class. `abstract final class` forbids direct instantiation everywhere and every kind of outside subtyping, and says so in the declaration instead of relying on a convention.
  • In Dart 3, why is `abstract interface class` preferred over a plain `abstract class` for a contract?
    A plain abstract class can be both extended and implemented, so readers cannot tell which is intended, and extenders couple to any code you later add. `interface` states that implementing is the only supported use and stops outside code from inheriting method bodies.

saying these in an interview costs you the question

  • abstract sealed class is the correct way to write a sealed type.
  • Dart has a standalone interface keyword separate from class.
  • A class can be both final and base for extra safety.
  • Enums can be marked sealed to restrict their values.
  • abstract final class can still be extended in other libraries.