Dart Fundamentals: The Language Behind Flutter · Classes, Modern Dart 3 Features and Async

Inheritance, Interfaces, Mixins and Extensions

Reuse behaviour with extends, define contracts with abstract classes and implements, share capabilities across unrelated classes with mixins, and add methods to existing types with extension methods.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

A small media library: an abstract Media class, Song and Podcast subclasses, a Playable interface, a Rateable mixin shared by both, and extension methods on Duration and String.

The idea

  • extends: single inheritance; a subclass inherits fields and methods and can @override them, calling super.
  • abstract class: can't be instantiated; declares methods subclasses must implement.
  • implements: every class is also an interface; implements means "I promise to provide all these members" (nothing is inherited).
  • Mixins (mixin Rateable { ... } then class Song extends Media with Rateable) add reusable behaviour to classes that don't share a parent.
  • Extension methods add methods to existing types, even ones you don't own: extension on Duration { String get mmss => ... }.
  • Dart 3 class modifiers (final, base, interface, sealed) control how others may extend or implement your classes.

The code

extends, implements, with and extension
abstract class Media {
  final String title;
  final Duration length;
  Media(this.title, this.length);
  String describe(); // subclasses must implement
}

abstract interface class Playable {
  String play();
}

mixin Rateable {
  final List<int> _ratings = [];
  void rate(int stars) => _ratings.add(stars.clamp(1, 5));
  double get rating => _ratings.isEmpty ? 0 : _ratings.reduce((a, b) => a + b) / _ratings.length;
}

extension on Duration {
  String get mmss => '${inMinutes}:${(inSeconds % 60).toString().padLeft(2, '0')}';
}

extension Shout on String {
  String shout() => '${toUpperCase()}!';
}

class Song extends Media with Rateable implements Playable {
  final String artist;
  Song(super.title, super.length, this.artist);
  @override
  String describe() => '$title by $artist (${length.mmss})';
  @override
  String play() => 'Playing song: $title';
}

class Podcast extends Media with Rateable implements Playable {
  final int episode;
  Podcast(super.title, super.length, this.episode);
  @override
  String describe() => '$title #$episode (${length.mmss})';
  @override
  String play() => 'Streaming episode $episode of $title';
}

void main() {
  final library = <Media>[
    Song('Blue in Green', const Duration(minutes: 5, seconds: 37), 'Miles Davis'),
    Podcast('Dart Weekly', const Duration(minutes: 42, seconds: 5), 112),
  ];

  for (final item in library) {
    print(item.describe());
    if (item is Playable) print('  ${(item as Playable).play()}');
    if (item is Rateable) {
      final rateable = item as Rateable;
      rateable..rate(5)..rate(4)..rate(9); // 9 is clamped to 5
      print('  rating: ${rateable.rating.toStringAsFixed(2)}');
    }
  }
  print('new release'.shout());
}

Output

Blue in Green by Miles Davis (5:37)
  Playing song: Blue in Green
  rating: 4.67
Dart Weekly #112 (42:05)
  Streaming episode 112 of Dart Weekly
  rating: 4.67
NEW RELEASE!

Run this on your computer — see “Get Started” for setup.

Common mistakes

  • Deep inheritance hierarchies. Prefer composition and mixins for shared behaviour.
  • implements when you meant extends. implements inherits nothing; you must write every member.
  • Mixins with constructors. Mixins can't declare constructors; keep their state simple.
  • Extension method conflicts. Two extensions adding the same name to one type cause ambiguity; name your extensions and import selectively.

Key points

  • extends for single inheritance, abstract for must-implement contracts.
  • implements treats any class as an interface.
  • with mixes in reusable behaviour across unrelated classes.
  • Extensions add methods to existing types; class modifiers control extension.

Further reading: Extend a class, Mixins, Extension methods, Class modifiers.

Practice questions

What's the difference between extends, implements and with in Dart?

Answer

extends inherits implementation from one superclass; implements promises to provide every member of the given interfaces without inheriting code; with applies mixins, adding their members to the class.

What are extension methods?

Answer

A way to add methods, getters or operators to an existing type (even one from another library) without subclassing it, e.g. extension on Duration { String get mmss => ...; }.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?