What is the difference between extends, implements, and with?
4 min read
OOP in Dart
| Keyword | Relationship | Inherits implementation? | Multiple? |
|---|---|---|---|
extends | IS-A (subclass) | ✅ Yes | ❌ One parent only |
implements | CAN-DO (interface contract) | ❌ No — you write it all | ✅ Many |
with | HAS-ABILITY (mixin) | ✅ Yes (copy-paste in) | ✅ Many |
Mental model: extends says "I am a kind of X", implements says "I behave like X", with says "I can do what X does."
Code in action
abstract class Animal {
final String name;
Animal(this.name);
void breathe() => print('$name breathes');
}
// extends — Dog IS an Animal, reuses breathe()
class Dog extends Animal {
Dog(super.name);
void bark() => print('$name: woof!');
}
// implements — Robot has no real "Animal" nature,
// but must provide every member itself
class Robot implements Animal {
@override final String name;
Robot(this.name);
@override
void breathe() => print('$name: simulated breathing');
}
// with — mixins add abilities without an IS-A claim
mixin Swimming { void swim() => print('swimming'); }
mixin Flying { void fly() => print('flying'); }
class Duck extends Animal with Swimming, Flying {
Duck(super.name);
}
void main() {
Duck('Donald')..breathe()..swim()..fly();
}
Mixin constraints with on
// "on Animal" means this mixin can ONLY be used by Animal (or subclasses)
mixin Barking on Animal {
void bark() => print('$name barks!');
}
class Hound extends Animal with Barking { Hound(super.name); }
// class Toaster with Barking {} // ❌ Toaster isn't an Animal
on lets a mixin safely call members of the base class (name here would be unreachable otherwise).
Combining all three
abstract class Animal { String get name; void breathe(); }
mixin Swimming { void swim() => print('swimming'); }
class Performer { void perform() => print('performing'); }
class Dolphin extends Animal
with Swimming
implements Performer {
@override final String name = 'Dolphin';
@override void breathe() => print('Surfacing');
@override void perform() => print('Splash show');
}
The required order is: class X extends Parent with Mixin1, Mixin2 implements Interface1, Interface2.
When to use which
| Situation | Pick |
|---|---|
Real "is-a" with shared behaviour (e.g. class AdminUser extends User) | extends |
| You need to enforce a contract / fake a class for tests | implements |
Cross-cutting capability shared by unrelated classes (Logging, Disposable) | with (mixin) |
| You want to compose multiple parent behaviours | with (Dart has no multiple extends) |
Common mistakes to avoid
// ❌ Using extends for "code reuse" when there's no IS-A
class CartScreen extends ApiHelper { ... } // CartScreen is not an ApiHelper
// ✅ Inject ApiHelper, or use a mixin if it's truly cross-cutting
// ❌ implements forces you to reimplement *everything*
class Cat implements Animal {
// forgot to override breathe() → compile error
}
// ✅ Use extends if you want to inherit the implementation
// ❌ Deep inheritance chains (3+ levels) — fragile and hard to test
class A {} class B extends A {} class C extends B {} class D extends C {}
// ✅ Prefer composition + mixins
// ❌ Forgetting @override — silently shadows instead of overriding
class Dog extends Animal {
void bark() => print('woof'); // missing @override on a method that exists in parent
}
// ❌ Calling super in the wrong order on initialisation
class Dog extends Animal {
Dog(String name) { // ❌ field initialisers run BEFORE super
super.name = name;
}
}
// ✅ Use super in the initialiser list or super-parameters
class Dog extends Animal {
Dog(super.name);
}
Interview follow-ups
-
Why does Dart only allow single inheritance with
extends? To avoid the diamond problem — ambiguous method resolution when two parents define the same method. Dart compensates with mixins (linearised in a defined order) and interfaces (no inherited behaviour to clash). -
Can any class be used as an interface? Yes — every class in Dart implicitly defines an interface.
implements SomeClassmeans "I promise to provide every public member SomeClass has." That's why testing libraries canimplements ApiClientto make fakes. -
What is mixin linearisation? When you write
class X extends A with M1, M2, Dart layers them asA → M1 → M2 → X. Method lookup walks up this chain, so a method inM2overrides the same method inM1.super.method()insideM2callsM1's version. -
mixinkeyword vs using a regular class as a mixin — what's the difference? Declaringmixin Foomakes it explicitly a mixin (it can't be instantiated or extended), and you can useonto constrain it. Using a plain class as a mixin still works in older Dart but is being phased out —mixin classexists for backwards compatibility.
How helpful was this content?
Please sign in to rate this article.