Sitemap
Aly Route

Aly Route

14.Mixins

4 min readApr 10, 2026

--

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 plop

Advanced 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 BaseWidget

Use on clause when:

  1. The mixin needs to call super.
  2. 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 on clause and no extends clause).
// 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 class cannot have an extends or with clause.
  • No on clause: While standard mixins use the on clause to restrict their application to certain superclasses, regular classes do not support this syntax. Therefore, a mixin class cannot use an on clause.
  • No generative constructors: Mixins cannot declare generative constructors (constructors that create an instance of the class and initialize fields), so a mixin class is also prohibited from having them.

Test Your Knowledge

--

Mobile Dev [Flutter - Kotlin]

See more from me