1

Mixins in Dart – Understand Dart & Flutter Fundamentals (Tutorial)

In a classic object oriented programming you have regular classesabstract classes and interfaces. Of course, Dart has its own take on interfaces, but that's for another tutorial...  Somewhere in the shadows though is lurking another kind of an animal. Mixins! What are they for and when should you use them? Let's find out.

World without mixins

Imagine you are building a wildlife simulation app which needs to have a Mosquito class. As an experienced and foreseeing developer, you extract the things mosquitoes have in common with other similar insects into abstract classes.

flying_things.dart

abstract class Insect {
  void crawl() {
    print('crawling');
  }
}

abstract class AirborneInsect extends Insect {
  void flutter() {
    print('fluttering');
  }

  void buzz() {
    print('buzzing annoyingly')
  }
}

class Mosquito extends AirborneInsect {
  void doMosquitoThing() {
    crawl();
    flutter();
    buzz();
    print('sucking blood');
  }
}

Awesome! You've done it! Adding new insects will go like a breeze without any code duplication... until you realize you also want to have a Swallow class (something has to eat all the mosquitoes, after all).

Again, there are some actions which all birds have in common, so you create an abstract Bird class. Then it strikes you - birds flutter their wings too! But you cannot extract the flutter method out of the AirborneInsect class into a new class called Fluttering.

Why? While Bird could extend Fluttering, this wouldn't be possible with AirborneInsect because it already extends Insect. Dart simply doesn't support multiple inheritance (which is a good thing).

Oh no, you need to add the flutter method into the Bird class too! Code duplication awaits.

flying_things.dart

abstract class Bird {
  void chirp() {
    print('chirp chirp');
  }

  // Duplicate method
  void flutter() {
    print('fluttering');
  }
}

class Swallow extends Bird {
  void doSwallowThing() {
    chirp();
    flutter();
    print('eating a mosquito');
  }
}

Using Mixins

Mixins are defined in the Dart documentation as "a way of reusing a class’s code in multiple class hierarchies". Simply said, mixins allow you to plug in blocks of code without needing to create subclasses. Declaring a mixin is very simple:

mixin Fluttering {
  void flutter() {
    print('fluttering');
  }
}

This mixin can be mixed into regular classes and abstract classes using the with keyword. In the wildlife simulation app's case, you'd probably use it on the abstract classes.

flying_things.dart

mixin Fluttering {
  void flutter() {
    print('fluttering');
  }
}

abstract class Insect {
  void crawl() {
    print('crawling');
  }
}

abstract class AirborneInsect extends Insect with Fluttering {
  void buzz() {
    print('buzzing annoyingly');
  }
}

class Mosquito extends AirborneInsect {
  void doMosquitoThing() {
    crawl();
    flutter();
    buzz();
    print('sucking blood');
  }
}

abstract class Bird with Fluttering {
  void chirp() {
    print('chirp chirp');
  }
}

class Swallow extends Bird {
  void doSwallowThing() {
    chirp();
    flutter();
    print('eating a mosquito');
  }
}
You can use multiple mixins on a single class. Should you want to reuse the "chirping" of birds, you could create Chirping mixin and use it together with Fluttering on the Bird class.
abstract class Bird with Fluttering, Chirping
There is no limit on how many mixins can a class mix in 😉

Limiting the use of Mixins

Sometimes you want to prevent a mixin from being used on any old class. Instead, you want to limit a mixin to be used only on a certain class or its subclass. This usually happens because you rely on certain methods or fields being already present.

In the case of the wildlife app, you realize that supporting just a swallow is not enough. There are other birds like sparrows and blue jays too! Unlike swallows, most of the other birds constantly peck something from the ground - seed here, earthworm there... 

Adding a method to the Bird abstract class is not possible, because not all birds peck. So, to prevent code duplication, you create a mixin called Pecking.

mixin Pecking {
  void peck() {
    print('pecking');
  }
}

Alright, this is better than code duplication but even overlooking the fact that now you can use the Pecking mixin even on the Insect classes, there's a much bigger issue with a mixin like this. Once you start researching the behavior of birds in their natural habitat, you come to a conclusion that after pecking something from the ground, birds start chirping out of sheer happiness.

Calling the chirp method from the current form of the mixin is not possible. The fix is simple though - just tell Dart to restrict the usage of the Pecking mixin to Bird classes. Now, accessing Bird's methods will go without a problem.

flying_things.dart

...
mixin Pecking on Bird {
  void peck() {
    print('pecking');
    chirp();
  }
}

class Sparrow extends Bird with Pecking {}

class BlueJay extends Bird with Pecking {}

Conclusion

Mixins are a very useful way of avoiding code duplication without inheritance. The fact that mixins can be also limited to work only with a particular class makes them powerful allies in the development of your apps.

Matej Rešetár
 

Matej is an app developer with a knack for teaching others. If he's not programming, making tutorials or doing other business, he's mostly working out, listening to audiobooks and taking cold showers.

  • Ryan Edge says:

    What are some good example use cases for mixins in Flutter?

  • >