Mixins

Dart · Practical · 10 min

Flutter uses mixins heavily, such as TickerProviderStateMixin and ChangeNotifier, and they solve multiple-inheritance needs.

A mixin is a bundle of fields and methods that can be added to many classes without inheritance:

mixin Logger {
  void log(String msg) => print('[$runtimeType] $msg');
}
class Service with Logger { }

A class lists mixins after with, optionally after extends: class Bird extends Animal with Flying, Singing. The mixins are applied left to right, each layered on top of the previous one, so a later mixin can override a method from an earlier one and reach it through super. This linearization is how Dart avoids the diamond problem.

Restrict where a mixin can be used with on: mixin Walker on Animal can only be applied to subclasses of Animal, and inside it you can call Animal's members and super.

Mixins can't have generative constructors. Since Dart 3, a class can only be used as a mixin if declared with mixin or mixin class (the latter is usable both as a normal class and a mixin).

In Flutter you'll write class _MyState extends State<MyWidget> with SingleTickerProviderStateMixin to give a state object the ability to drive animations, and models often use with ChangeNotifier or extends ChangeNotifier.

Prefer mixins for small, orthogonal capabilities. If you find a mixin needing lots of state from its host, composition (a field holding a helper object) may be clearer.

Example

abstract class Animal {
  String get name;
  String move() => '$name moves';
}
mixin Swimmer on Animal {
  @override
  String move() => '${super.move()} and swims';
}
mixin Flyer on Animal {
  @override
  String move() => '${super.move()} and flies';
  int altitude = 0;
}

class Duck extends Animal with Swimmer, Flyer {
  @override
  String get name => 'Duck';
}

void main() {
  final d = Duck()..altitude = 30;
  print(d.move());           // Duck moves and swims and flies
  print(d is Swimmer);       // true
  print(d.altitude);         // 30
}

Remember

  • with A, B layers mixins left to right; later ones override earlier ones
  • mixin M on Base restricts use and allows super calls
  • Mixins have no constructors; declare with mixin or mixin class

Watch out for

  • Relying on mixin order without realizing a later mixin silently overrides an earlier method.

Check yourself

  1. `class C extends Base with A, B` and both A and B override `run()`, calling super. Which runs first when calling `C().run()`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: dart.dev/language/mixins