๐ŸŽ“ A1Learner
๐Ÿ”
0 of 37 lessons completed

Dart Mixins in Depth

A mixin adds methods and fields to a class without being a parent class. The with keyword applies a mixin to a class.

One mixin, unrelated classes

Dog and Robot share no parent class. The Greeter mixin gives both of them the same greet method.

mixin Greeter {
  void greet() {
    print('Hello');
  }
}

class Dog with Greeter {}

class Robot with Greeter {}

void main() {
  var dog = Dog();
  dog.greet();
  var robot = Robot();
  robot.greet();
}

A mixin with state

The Counter mixin holds its own count field. Each bump call raises the count and prints it.

mixin Counter {
  int count = 0;

  void bump() {
    count = count + 1;
    print('Count: $count');
  }
}

class Game with Counter {}

void main() {
  var game = Game();
  game.bump();
  game.bump();
}

The last mixin wins

Both mixins override describe and pass the call on with super. Swimmer sits last in the with list, so its version is found first and its line prints last.

class Animal {
  void describe() {
    print('Animal');
  }
}

mixin Walker on Animal {
  @override
  void describe() {
    super.describe();
    print('Walker');
  }
}

mixin Swimmer on Animal {
  @override
  void describe() {
    super.describe();
    print('Swimmer');
  }
}

class Duck extends Animal with Walker, Swimmer {}

void main() {
  var duck = Duck();
  duck.describe();
}

An on constraint

The on Animal line limits Swimmer to subclasses of Animal. Fish extends Animal, so Fish may use the mixin.

class Animal {
  String name;

  Animal(this.name);
}

mixin Swimmer on Animal {
  void swim() {
    print('$name swims');
  }
}

class Fish extends Animal with Swimmer {
  Fish(super.name);
}

void main() {
  var fish = Fish('Nemo');
  fish.swim();
}

Example

mixin Announcer {
  int times = 0;

  void announce(String word) {
    times = times + 1;
    print('$word ($times)');
  }
}

class Bell with Announcer {}

class Horn with Announcer {}

void main() {
  var bell = Bell();
  bell.announce('Ding');
  bell.announce('Ding');
  var horn = Horn();
  horn.announce('Beep');
}

Key points

  • A mixin is declared with the mixin keyword.
  • The with keyword adds a mixin to a class.
  • One mixin can serve classes that share no parent.
  • A mixin can hold fields, so it can carry its own state.
  • When two mixins override the same method, the last one in the with list wins.
  • The on keyword limits a mixin to subclasses of one named class.

In this example, one mixin serves two unrelated classes. Each object carries its own counter from the mixin, so the bell reaches 2 while the horn starts at 1.

Note

A mixin is not a class, so no class can extend a mixin.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท DartPad

Exercise

Two mixins override the same method. Which one wins?