What is the difference between extends, implements, and with?

Medium PriorityAsked in ~65% of Flutter interviews

4 min read

OOP in Dart

KeywordRelationshipInherits implementation?Multiple?
extendsIS-A (subclass)✅ Yes❌ One parent only
implementsCAN-DO (interface contract)❌ No — you write it all✅ Many
withHAS-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

SituationPick
Real "is-a" with shared behaviour (e.g. class AdminUser extends User)extends
You need to enforce a contract / fake a class for testsimplements
Cross-cutting capability shared by unrelated classes (Logging, Disposable)with (mixin)
You want to compose multiple parent behaviourswith (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

  1. 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).

  2. Can any class be used as an interface? Yes — every class in Dart implicitly defines an interface. implements SomeClass means "I promise to provide every public member SomeClass has." That's why testing libraries can implements ApiClient to make fakes.

  3. What is mixin linearisation? When you write class X extends A with M1, M2, Dart layers them as A → M1 → M2 → X. Method lookup walks up this chain, so a method in M2 overrides the same method in M1. super.method() inside M2 calls M1's version.

  4. mixin keyword vs using a regular class as a mixin — what's the difference? Declaring mixin Foo makes it explicitly a mixin (it can't be instantiated or extended), and you can use on to constrain it. Using a plain class as a mixin still works in older Dart but is being phased out — mixin class exists for backwards compatibility.

How helpful was this content?

Please sign in to rate this article.