Abstract Classes and Interfaces
As your programs grow, you often want to say "these things must all be able to do X" without caring how they do it. Dart gives you two tools for that: abstract classes and interfaces. This chapter shows what each one is, when to reach for it, and how to check types at runtime.
The Problem: A Promise Without an Implementation
An abstract class is a class that cannot be created directly. It exists to describe what its children must do. Some of its methods may have no body at all — just a name and a return type. Each child class must fill in the missing pieces.
abstract class Shape {
double area(); // no body: every shape must define this
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
@override
double area() => 3.14159 * radius * radius;
}
void main() {
final Shape s = Circle(2); // a Circle stored as a Shape
print(s.area()); // 12.56636
if (s is Circle) print('radius: ${s.radius}');
}Notice two things:
Shape s = Circle(2)— the variable's type isShape, but the object inside is aCircle. You can calls.area()because everyShapepromises anarea().s is Circle— theisoperator checks what the object really is at runtime. This is called a type check.
If you tried Shape s = Shape();, the compiler would refuse. Abstract classes are promises, not things.
Interfaces: Dart's Simpler Take
In many languages, "interface" is a separate keyword with strict rules. Dart keeps it simple: every class is automatically an interface. When you use the implements keyword, you promise to provide your own version of every member of that class — fields, getters, methods, all of them. Nothing is inherited; you rebuild it all.
class Printable {
String describe() => 'a printable thing';
}
class Report implements Printable {
@override
String describe() => 'a quarterly report'; // you must redefine everything
}Choosing Between extends and implements
Use extends when the parent has useful code you want to inherit. Use implements when you only care about the shape of the API and will write the body yourself. Abstract classes are ideal when you want both: some shared code plus required methods each child must complete.
Why This Matters
Abstract types let you write functions like void render(Shape s) that work with any shape — current or not yet written. The compiler enforces the promise, so mistakes surface before the program ever runs.
Exercise
What happens if a class uses implements Shape but does not define area()?
Show answer
The compiler reports an error. Implementing a class means you must provide every member yourself, including area().
Exercise
Can you create an instance of an abstract class with new or a constructor call?
Show answer
No. Abstract classes exist only to be extended or implemented; direct creation is a compile-time error.
Spotted a mistake, or code that does not work?