In a classic object oriented programming you have regular classes, abstract 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');
}
}
abstract class Bird with Fluttering, Chirping
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.
What are some good example use cases for mixins in Flutter?
TickerProviderStateMixin for animations.
Thank youuuu
I don’t think the title of your article matches the content lol. Just kidding, mainly because I had some doubts after reading the article.
Your article helped me a lot, is there any more related content? Thanks!
Thanks for sharing. I read many of your blog posts, cool, your blog is very good.
I don’t think the title of your enticle matches the content lol. Just kidding, mainly because I had some doubts after reading the enticle.
Thank you for your sharing. I am worried that I lack creative ideas. It is your article that makes me full of hope. Thank you. But, I have a question, can you help me?