14.Mixins
Mixins are a way of defining code “fields and methods” that can be reused in multiple class hierarchies.
Why Mixins?
// No problem
abstract class Bird {
void fly();
void layEggs();
}
class Robin extends Bird {
@override
void fly() {
print('Swoosh swoosh');
}
@override
void layEggs() {
print('Plop plop');
}
}
// duplicating layEggs
abstract class Animal {
bool isAlive = true;
void eat();
void move();
@override
String toString() {
return "I'm a $runtimeType";
}
}
class Platypus extends Animal {
@override
void eat() {
print('Munch munch');
}
@override
void move() {
print('Glide glide');
}
// the same implementation
void layEggs() {
print('Plop plop');
}
}Your layEggs code for Robin is exactly the same as it is for Platypus . That means you’re duplicating code, which violates the DRY principle. If there are any future changes to layEggs you’ll have to remember to change both instances.
Create a Mixin
To make a mixin, you take whatever concrete code you want to share with different classes, and package it in its own special mixin class.
mixin EggLayer {
void layEggs() {
print('Plop plop');
}
}
mixin Flyer {
void fly() {
print('Swoosh swoosh');
}
}The mixin keyword indicates that these classes can only be used as mixins. You can also use a normal class as a mixin as long as that class doesn’t extend another non- Object class.
- Now refactor Robin as follows, using the with keyword to identify the mixins:
class Robin extends Bird with EggLayer, Flyer {}- Refactor Platypus as well
class Platypus extends Animal with EggLayer {
@override
void eat() {
print('Munch munch');
}
@override
void move() {
print('Glide glide');
}
}- Now both Robin and Platypus share the code that the EggLayer mixin contains. Just to make sure it works, run the following code:
final platypus = Platypus();
final robin = Robin();
platypus.layEggs(); // Plop plop
robin.layEggs(); // Plop plopAdvanced Mixin Techniques
Defining Abstract Members
You can declare an abstract method or getter in a mixin. This forces any class using the mixin to provide an implementation for those members.
mixin ValidationMixin {
// Subclass must provide this value
abstract final String inputData;
bool isValid() => inputData.isNotEmpty;
}
class LoginForm with ValidationMixin {
@override
String inputData = "User123"; // Providing state for the mixin
}Get Aly Route’s stories in your inbox
Join Medium for free to get updates from this writer.
The on Clause (Superclass Restriction)
The on clause restricts a mixin so it can only be used by classes that extend or implement a specific type.
class BaseWidget {}
// This mixin can ONLY be used by classes that extend BaseWidget
mixin AnimationMixin on BaseWidget {
void play() {
print("Playing animation...");
}
}
class MyWidget extends BaseWidget with AnimationMixin {} // Correct
// class MyData with AnimationMixin {} // Error: MyData doesn't extend BaseWidgetUse on clause when:
- The mixin needs to call
super. - The mixin depends on members belonging to a specific superclass.
// The specific superclass type
abstract class BaseService {
void initialize() {
print("Service: Initializing system...");
}
void shutdown() {
print("Service: Systems offline.");
}
}
// This mixin depends on BaseService members and needs to call 'super'
mixin AnalyticsMixin on BaseService {
@override
void initialize() {
// The 'on' clause allows this super call
super.initialize();
print("Analytics: Tracking system startup.");
}
void trackShutdown() {
// Accessing a member from the superclass (BaseService)
shutdown();
print("Analytics: Shutdown logged.");
}
}
// VALID: MyService extends BaseService, so it can use the mixin
class MyService extends BaseService with AnalyticsMixin {}
void main() {
var service = MyService();
service.initialize(); // Calls BaseService.initialize AND AnalyticsMixin logic
service.trackShutdown(); // Uses inherited shutdown() and mixin logic
}mixins rules
- No Constructors: Mixins cannot declare any generative constructors.
- No Extension: Mixins cannot have an extends clause.
- State Management: Because they lack constructors, mixins cannot use constructor parameters to initialize their own fields
Mixin Classes
Mixin class acts as both a regular class (you can instantiate it) and a mixin (you can use it with with).
- They share the same name and type regardless of how they are used.
- They must follow both class and mixin rules (e.g., no
onclause and noextendsclause).
// 1. Defining the mixin class
// Rule: No 'extends', no 'on' clause, and no generative constructors.
mixin class diagnosticTools {
void performSelfTest() {
print("Running diagnostic self-test...");
}
}
// 2. Usage as a regular Class
void useAsClass() {
// You can instantiate it directly like a normal class
var tools = diagnosticTools();
tools.performSelfTest();
}
// 3. Usage as a Mixin
// It is mixed into the class hierarchy using 'with'
class NetworkRouter with diagnosticTools {
void start() {
print("Router starting...");
performSelfTest(); // Accessing mixin functionality
}
}
void main() {
useAsClass();
var router = NetworkRouter();
router.start();
// Both uses share the same type identity for 'diagnosticTools'
print(router is diagnosticTools); // Output: true
}Because a mixin class must satisfy the requirements of both a class and a mixin, it is subject to the following strict rules:
- No extends or with clauses: Mixins are not allowed to extend other classes, so a
mixin classcannot have anextendsorwithclause. - No on clause: While standard mixins use the
onclause to restrict their application to certain superclasses, regular classes do not support this syntax. Therefore, amixin classcannot use anonclause. - No generative constructors: Mixins cannot declare generative constructors (constructors that create an instance of the class and initialize fields), so a
mixin classis also prohibited from having them.







