# Mixins

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Object-Oriented Programming
Source: https://www.devtutorials.ai/learn/dart/object-oriented/mixins-and-callable-classes

> How to add ready-made abilities to classes with mixins, make callable classes, and add methods to existing types like String and List with extensions and extension types.

## What Are Mixins?

**Mixin** = a bundle of methods (and fields) that you can **add to** any class, without making it a parent.

- You write it with the `mixin` keyword.
- You add it to a class with the `with` keyword.
- One class can take **many** mixins.
- So a class can gain abilities from many places, while still having only **one** parent.

**Simple lesson:** a mixin is a ready-made ability you can plug into a class.

### A Real-World Example

Think of badges on a school blazer.

- **Swimming** badge, **First Aid** badge, **Debate** badge.
- Any student can earn any badge. A badge is not a parent of the student.
- Two very different students can wear the same badge.
- A mixin is a badge: `class Ravi extends Student with Swimmer, FirstAider`.

Toggle the mixins and see the order Dart uses to find a method:

Every **Run** box on this page runs on the course's Dart runner in your browser.

In **Inheritance** you saw that Dart does not allow two parents. Mixins are the answer to that problem.

## What You Will Learn

In this lesson, you will learn:

1. How to write a mixin and add it with `with`, and which one wins a name clash.
2. How `on` limits a mixin, and how mixins compare with inheritance.
3. How a `call()` method makes an object callable.
4. How to add methods to existing types with extensions.
5. What extension types are, and when to use them.

## Creating and Using Mixins

### The mixin Keyword

```text
mixin Name {
  // fields and methods
}

class Child extends Parent with Name { }
```

```dart runnable title="A swimming ability for anyone"
mixin Swimmer {
  void swim() => print('Swimming a lap!');
}

class Student {
  final String name;
  Student(this.name);
}

class SwimmingStudent extends Student with Swimmer {
  SwimmingStudent(super.name);
}

class Duck with Swimmer {}

void main() {
  SwimmingStudent('Ravi').swim();
  Duck().swim();
  print(Duck() is Swimmer);
}
```

- A student and a duck are not related, but both can swim.
- A mixin can be used **without** `extends` too: `class Duck with Swimmer`.
- An object with a mixin **is** that mixin type: `Duck() is Swimmer` is `true`.

### Mixins with Fields

A mixin can keep its own data:

```dart runnable title="A counter you can add to any class"
mixin Counter {
  int count = 0;
  void increment() => count++;
}

class Gate with Counter {
  void open() {
    increment();
    print('Gate opened. Total: $count');
  }
}

void main() {
  var g = Gate();
  g.open();
  g.open();
  g.open();
}
```

**Simple lesson:** write the ability once as a mixin, then add it with `with` wherever it is needed.

## Multiple Mixins and Their Order

### Using Several Mixins

```dart runnable title="A sports captain with three badges"
mixin Runner {
  void run() => print('Running 100 m');
}

mixin Swimmer {
  void swim() => print('Swimming 50 m');
}

mixin Leader {
  void lead() => print('Leading the team');
}

class Student {
  final String name;
  Student(this.name);
}

class Captain extends Student with Runner, Swimmer, Leader {
  Captain(super.name);
}

void main() {
  var c = Captain('Meena');
  print('${c.name} can:');
  c.run();
  c.swim();
  c.lead();
}
```

### When Two Mixins Have the Same Method

Mixins are stacked **in the order you write them**. The **last** one is on top, so it wins:

The order after `with` matters when names clash. The **last** mixin wins.

Try to give mixins different method names, so the order does not surprise anyone.

**Simple lesson:** many mixins are fine, and if two share a name, the last one listed wins.

## The on Keyword

**`on` constraint** = `mixin Name on SomeClass` means the mixin can **only** be used by classes that extend (or implement) `SomeClass`.

- The mixin can then safely use members of `SomeClass`.
- Dart stops anyone from adding it to the wrong class.

```dart runnable title="Only performers can sing on stage"
class Performer {
  final String name;
  Performer(this.name);
  void bow() => print('$name bows.');
}

mixin Singer on Performer {
  void sing() {
    print('$name sings the school song.');
    bow();
  }
}

class Student extends Performer with Singer {
  Student(super.name);
}

void main() {
  Student('Priya').sing();
}
```

- `Singer` uses `name` and `bow()`. They exist because of `on Performer`.
- `class Robot with Singer {}` would be a compile error: a `Robot` is not a `Performer`.

**Simple lesson:** `on` says "this badge is only for members of this family".

## Mixins, Inheritance and Interfaces

| | `extends` | `implements` | `with` (mixin) |
|---|---|---|---|
| How many? | one | many | many |
| Gets code? | yes | no | yes |
| Must write every member? | no | yes | no |
| Meaning | **is a** | **promises to act like** | **has the ability** |
| Example | `Student extends Person` | `Fan implements Switchable` | `Duck with Swimmer` |

### mixin class

**`mixin class`** = a class that can **also** be used as a mixin. Use it when you want both: objects of it, and its abilities in other classes.

```dart
mixin class Logger {
  void log(String m) => print('[log] $m');
}

var l = Logger();           // works: it is a class
class Library with Logger {} // works: it is a mixin
```

**Easy way to remember**

- `extends`: **is a** (one family).
- `implements`: **promises** (many contracts, no code).
- `with`: **can do** (many abilities, with code).

**Simple lesson:** use mixins for shared abilities that do not fit one family tree.

## Callable Classes

**Callable class** = a class with a method named **`call()`**. Its objects can be called **like functions**: `obj(5)`.

```dart runnable title="A fee calculator you call like a function"
class FeeCalculator {
  final int perMonth;
  FeeCalculator(this.perMonth);

  int call(int months) => perMonth * months;
}

void main() {
  var fee = FeeCalculator(1200);
  print(fee(3));
  print(fee(12));
  print(fee.call(1));
}
```

- `fee(3)` is a short way of writing `fee.call(3)`.
- Unlike a plain function, the object can **keep data**, like `perMonth`.

```dart runnable title="A callable object that remembers"
class Attendance {
  final List<String> present = [];

  void call(String name) {
    present.add(name);
    print('$name marked present (${present.length})');
  }
}

void main() {
  var mark = Attendance();
  mark('Asha');
  mark('Ravi');
  mark('Imran');
  print(mark.present);
}
```

**Simple lesson:** give a class a `call()` method, and its objects work like functions that remember things.

## What Are Extensions?

**Extension method** = a new method or getter that you **add to an existing type**, even one you did not write, like `String` or `int`.

- You cannot open Dart's `String` class and edit it.
- But you can write `extension ... on String { ... }`.
- After that, every String can use your new method, as if it was always there.

**Simple lesson:** an extension adds your own tools to a type you do not own.

### A Real-World Example

The school gives every student the same calculator.

- You cannot change how the calculator is built.
- But you can stick a small card on the back with your own shortcuts: "GPA = total ÷ 5".
- The calculator is the same. You just added a helper to it.
- An extension is that card, stuck on `String`, `List` or `DateTime`.

Here is the difference between a helper function and an extension:

Extension **types** (the last part of this lesson) are shown in plain boxes. The runner does not support them yet.

## Extension Methods

### Writing One

```text
extension Name on Type {
  // methods and getters, using `this` for the value
}
```

```dart runnable title="A shout() method for every String"
extension Loud on String {
  String shout() => '${toUpperCase()}!';
}

void main() {
  print('hello'.shout());
  var name = 'asha';
  print(name.shout());
}
```

- Inside the extension, **`this`** is the value the method was called on.
- You may leave out `this.`: `toUpperCase()` means `this.toUpperCase()`.

### Extension Getters

Getters work too, read without `()`:

```dart runnable title="Getters on int"
extension AgeTools on int {
  bool get isTeen => this >= 13 && this <= 19;
  int get inMonths => this * 12;
}

void main() {
  var age = 14;
  print(age.isTeen);
  print(age.inMonths);
  print(9.isTeen);
}
```

**Simple lesson:** write `extension Name on Type`, and every value of that type gets your methods.

## Naming and Conflicts

### Named and Unnamed Extensions

- **Named:** `extension Loud on String`. You can refer to it by name, and import or hide it.
- **Unnamed:** `extension on String`. Usable only in the file where it is written.

```dart runnable title="An unnamed extension"
extension on String {
  String get initials => split(' ').map((w) => w[0]).join();
}

void main() {
  print('Green Valley School'.initials);
  print('Asha Kumari'.initials);
}
```

### When Names Clash

**Conflict** = two extensions add a member with the **same name** to the **same type**.

```dart
// in file a.dart
extension A on String { String tidy() => trim(); }
// in file b.dart
extension B on String { String tidy() => toLowerCase(); }

print(' Hi '.tidy());
// Error: A member named 'tidy' is defined in 'A' and 'B', and neither is more specific.
```

Three ways to fix it:

1. **Call it by name:** `A(' Hi ').tidy()`. The name picks the extension.
2. **Hide one:** `import 'b.dart' hide B;` (see **Libraries**).
3. **Rename** one of the methods.

```dart runnable title="Calling an extension by name"
extension Tidy on String {
  String tidy() => trim().toLowerCase();
}

void main() {
  print(Tidy('  HELLO  ').tidy());
}
```

A real member always wins over an extension.

If you write `extension on String { int get length => 0; }`, `'abc'.length` still gives `3`. Do not reuse names of real members.

**Simple lesson:** give extensions clear names, and call `Name(value).method()` when two of them clash.

## Practical Extensions

### On List and DateTime

```dart runnable title="Marks tools and date tools"
extension MarksTools on List<int> {
  int get total => fold(0, (a, b) => a + b);
  String get average => (total / length).toStringAsFixed(1);
  List<int> above(int limit) => where((m) => m > limit).toList();
}

extension SchoolDate on DateTime {
  bool get isWeekend => weekday == DateTime.saturday || weekday == DateTime.sunday;
  String get short => '$day/$month/$year';
}

void main() {
  var marks = [92, 85, 78, 64];
  print('Total: ${marks.total}');
  print('Average: ${marks.average}');
  print('Above 80: ${marks.above(80)}');

  var d = DateTime(2026, 11, 14);
  print('${d.short} is a weekend: ${d.isWeekend}');
}
```

- `on List<int>` means only lists of `int` get these tools. A `List<String>` does not.
- `MarksTools` uses `fold`, `length` and `where` of the list, through `this`.

Good extensions are **small** and **obvious**. `marks.average` is clear.

If an extension needs lots of data of its own, it should probably be a class instead.

**Simple lesson:** extensions make common jobs on built-in types short and readable.

## Extension Types

**Extension type** = a **new type** that **wraps** an existing value, with **no extra cost** while running.

- **Representation type** = the type inside, like `int` in `extension type StudentId(int value)`.
- The new type is **different** from `int` for Dart's checks, so you cannot mix them up.
- While running, it is just the `int`. Nothing extra is stored.

```dart
extension type StudentId(int value) {
  bool get isValid => value > 0;
}

extension type BookId(int value) {}

void issueBook(StudentId student, BookId book) {
  print('Book ${book.value} issued to student ${student.value}');
}

void main() {
  var s = StudentId(1042);
  var b = BookId(77);
  issueBook(s, b);   // Book 77 issued to student 1042
  issueBook(b, s);   // Error: The argument type 'BookId' can't be assigned to the parameter type 'StudentId'.
}
```

- With plain `int`, swapping the two IDs would compile and cause a silent bug.
- With extension types, Dart catches the swap **before** running.

### Extension Methods or Extension Types?

| | Extension method | Extension type |
|---|---|---|
| Adds a new type? | no | **yes** |
| Changes what you can pass where? | no | yes, `StudentId` is not `int` |
| Typical use | helpers on `String`, `List` | safe IDs, units like `Rupees` |
| Cost while running | none | none |

**Easy way to remember**

- `extension X on T` = **add tools** to every `T`.
- `extension type X(T v)` = **make a new label** for a `T`, so values are not mixed up.
- `X(value).method()` = **pick** an extension by name.

**Simple lesson:** extension methods add tools to a type, and extension types make a new, safer type from an old one.

## TL;DR

1. **`mixin M`** + **`class C with M`** adds abilities. With many mixins, the last one wins a name clash.
2. **`mixin M on P`** can only be used by classes that are a `P`.
3. **Callable class** = has `call()`, so `obj(x)` works like a function.
4. **`extension X on String { ... }`** adds methods and getters to an existing type.
5. **`extension type Id(int value)`** makes a new, safer type over an existing one.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `class C extends A, B` | Two parents are fine | Use `extends A with B` | A compile error. |
| `var m = Swimmer();` for a `mixin` | A mixin makes objects | Use it with `with`, or write `mixin class` | A compile error. |
| Ignoring mixin order | Order does not matter | The last mixin wins a name clash | The wrong method runs. |
| Using a mixin's `on` members in the wrong class | `on` is a hint | `on` is a strict rule | A compile error. |
| Naming the method `Call()` | Any case works | It must be exactly `call()` | The object is not callable. |
| Forgetting `on Type` | Extensions apply to all types | Write `extension X on String` | A compile error. |
| Naming a member like a real one | The extension replaces it | Real members always win | Your method is never called. |
| Two extensions with the same member | Dart picks one | Call `Name(value).m()`, or hide one | An ambiguity error. |
| Heavy logic in an extension | Extensions can hold state | Extensions cannot add fields | Use a class instead. |
| Expecting an extension type to be a full class | It is a new class | It is a zero-cost wrapper over one value | Wrong expectations about fields. |

## Check Yourself

## Exercises

## What to Remember

- Mixins add ready-made abilities without a second parent.
- The last mixin in the list wins a name clash.
- A class with `call()` makes objects you can call like functions.
- Extensions add tools to types you did not write, like String and List.
- Extension types stop values like IDs from being mixed up.

Next: **Class Modifiers**. You will control who can make, extend or implement your classes.
