Menu
Coddy logo textTech

Mixin vs Inheritance

Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 54 of 110.

Now that you've learned how mixins work, let's clarify when to use them instead of inheritance. The key difference lies in the relationship they express.

Inheritance represents an "is-a" relationship. A Dog is an Animal. The subclass is a specialized version of the parent, and you can only extend one class.

Mixins, on the other hand, represent a "can-do" relationship. A Dog can swim, but swimming isn't what defines a dog.

// Inheritance: Dog IS an Animal
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

// Mixin: Dog CAN swim (but isn't defined by swimming)
mixin Swimming {
  void swim() => print('Swimming');
}

class Dog extends Animal with Swimming {
  Dog(String name) : super(name);
}

Use inheritance when classes share a fundamental identity and you need constructors in the parent. Use mixins when you want to add capabilities to classes that don't share a common ancestor.

FeatureInheritanceMixin
Relationshipis-acan-do
LimitOne parent onlyMultiple mixins
ConstructorsAllowedNot allowed
Use caseSpecializationShared behavior

The best part? You can combine both - extend one class and mix in multiple capabilities, giving your classes exactly the features they need.

challenge icon

Challenge

Easy

Let's build a worker system that demonstrates when to use inheritance versus mixins. You'll create a base class for the "is-a" relationship and mixins for "can-do" capabilities, then combine them to show how both approaches work together.

You'll organize your code into three files:

  • worker.dart: Define your base class that establishes the core identity of all workers:
    • A Worker class with String name and String department properties. Include a constructor that takes both values. Add a method introduce() that prints [name] works in [department]
  • skills.dart: Define mixins that represent capabilities workers can have (the "can-do" relationships):
    • A CanCode mixin with a method writeCode() that prints Writing code...
    • A CanDesign mixin with a method createDesign() that prints Creating design...
    • A CanManage mixin with a method leadTeam() that prints Leading the team...
  • main.dart: Import both files and create specialized worker types that combine inheritance with mixins:
    • A Developer class that extends Worker and uses the CanCode mixin
    • A TechLead class that extends Worker and uses both CanCode and CanManage mixins
    • Create a Developer named 'Alice' in department 'Engineering'
    • Create a TechLead named 'Bob' in department 'Engineering'
    • For Alice: call introduce() then writeCode()
    • Print an empty line
    • For Bob: call introduce(), then writeCode(), then leadTeam()

Notice how both Developer and TechLead are workers (inheritance), but they can do different things (mixins). The TechLead combines multiple capabilities without needing multiple inheritance.

Expected output:

Alice works in Engineering
Writing code...

Bob works in Engineering
Writing code...
Leading the team...

Cheat sheet

Inheritance represents an "is-a" relationship (a subclass is a specialized version of the parent), while mixins represent a "can-do" relationship (adding capabilities without defining identity).

// Inheritance: Dog IS an Animal
class Animal {
  String name;
  Animal(this.name);
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

// Mixin: Dog CAN swim
mixin Swimming {
  void swim() => print('Swimming');
}

class Dog extends Animal with Swimming {
  Dog(String name) : super(name);
}
FeatureInheritanceMixin
Relationshipis-acan-do
LimitOne parent onlyMultiple mixins
ConstructorsAllowedNot allowed
Use caseSpecializationShared behavior

You can combine both approaches - extend one class and mix in multiple capabilities:

class TechLead extends Worker with CanCode, CanManage {
  TechLead(String name, String department) : super(name, department);
}

Try it yourself

import 'worker.dart';
import 'skills.dart';

// TODO: Create a Developer class that extends Worker and uses the CanCode mixin

// TODO: Create a TechLead class that extends Worker and uses both CanCode and CanManage mixins

void main() {
  // TODO: Create a Developer named 'Alice' in department 'Engineering'
  
  // TODO: Call introduce() then writeCode() for Alice
  
  // TODO: Print an empty line
  
  // TODO: Create a TechLead named 'Bob' in department 'Engineering'
  
  // TODO: Call introduce(), writeCode(), then leadTeam() for Bob
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming