Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Dart (3.13)  Module 9 – Inheritance, mixins, class modifiers and extensions

Mixins and the mixin class

Write a Dart mixin and a mixin class, apply them with `with`, use the `on` clause to call super, and predict how two mixins compose under linearization.

  • Intermediate
  • 15 minutes
  • Examples run with dart 3.13.5
  • By MySmartCoPilot
Free core, Pro depth: 6 of 15 minutes free
Free: A mixin adds members with · The clause opens and fixes where a mixin applies. With a pass: 2 in-depth parts and 3 interview answers, about 9 minutes.

What you will learn

  • Write a mixin and a mixin class, and apply them to a Notifier with `with`
  • Explain the on clause and the super chain of applied mixins
  • Predict which body runs for super.send under both orderings of a with list
  • Decide between a mixin, a base class and composition for a shared behaviour
  • Design a tiny host that tests a mixin without touching the real gateway

Before you start

What you’ll learn · Before you start

What you will learn

  • Write a mixin and a mixin class, and apply them to a Notifier with `with`
  • Explain the on clause and the super chain of applied mixins
  • Predict which body runs for super.send under both orderings of a with list
  • Decide between a mixin, a base class and composition for a shared behaviour
  • Design a tiny host that tests a mixin without touching the real gateway

Before you start

On this page

An SMS notifier and an email notifier both need a retry wrapper, a log line and a greeting template: three blocks of code, each written twice. Dart mixins remove that repetition: a mixin: A Dart declaration that adds its members to any class that lists it with the with keyword. A mixin cannot have an extends clause, cannot declare a generative constructor, and may name a superclass constraint with on. is a named block of fields and methods that classes add through the with keyword without changing their parent. Dart mixins suit behaviour that unrelated classes share, such as retries or logging, where a common base class would force them all under one parent.

You will write a mixin and a mixin class: A Dart declaration since 3.0 that is both a class (usable with extends) and a mixin (usable with with); it has the same restrictions as a mixin: no extends on itself, no generative constructor., which works both as a mixin and as a parent, and test the Dart 3.0 rule that a plain class cannot be mixed in. Then the on clause lets a mixin call super, and two mixins compose through mixin linearization: Dart's rule for stacking a with list: mixins are layered left to right in the declaration and bottom to top in the chain, so dispatch starts at the last mixin and super steps one slot down.. The outputs below are what each program printed on Dart 3.13.5.

A mixin adds members with with

A mixin declaration looks like a class but is used only through the with keyword, and the fields and methods it declares are added to every class that lists it. A mixin class can also stand alone as a parent after extends. This program applies both to the shop’s SMS notifier:

notifier.dart: the base Notifier and SmsNotifier Dart · notifier.dart
// notifier.dart: the shared abstract Notifier and a concrete SmsNotifier.
//
// The mixins lesson reuses the shape from dart/inheritance-and-interfaces: a
// Notifier that promises a single send, and an SmsNotifier that writes it to
// the console in the shop's shape. Nothing in this file is a mixin yet; it is
// the base every example extends.

abstract class Notifier {
  void send(String to, String text);
}

class SmsNotifier extends Notifier {
  final String sender;
  SmsNotifier(this.sender);

  @override
  void send(String to, String text) {
    print('[SMS from $sender] +91 $to: $text');
  }
}
mixin_basic.dart: a mixin Log, a mixin class Templated and one SmsNotifier Dart · mixin_basic.dart
// mixin_basic.dart: declare a mixin, declare a mixin class, and apply both
// with `with` to an SmsNotifier. The mixin adds a log method and a counter;
// the mixin class is reused as a plain parent too, which is what makes it
// "both a class and a mixin" (dart.dev/language/mixins, Dart 3.0).
//
// Run: dart run mixin_basic.dart

import 'notifier.dart';

mixin Log {
  int logs = 0;
  void log(String line) {
    logs++;
    print('[log] $line');
  }
}

// A `mixin class` can be used in both `extends` and `with`. The restrictions
// of a mixin apply (no extends on the declaration, no generative constructor).
mixin class Templated {
  String build(String name, String text) => 'Dear $name, $text';
}

class SmsWithLog extends SmsNotifier with Log, Templated {
  SmsWithLog(super.sender);
}

// Templated is also used as a plain parent class: the "class" half.
class EagerTemplate extends Templated {}

void main() {
  final s = SmsWithLog('MSCOPL');
  s.log('getting the message ready');
  final msg = s.build('Priya', 'Your order is on the way.');
  s.send('98765 43210', msg);

  final e = EagerTemplate();
  print(e.build('Kabir', 'Thanks for the review.'));
  print('log entries: ${s.logs}');
}

Output

[log] getting the message ready
[SMS from MSCOPL] +91 98765 43210: Dear Priya, Your order is on the way.
Dear Kabir, Thanks for the review.
log entries: 1

Recorded with Dart SDK 3.13.5 (stable) on macos_arm64 on macOS 26 arm64. To run it yourself: dart run mixin_basic.dart

The run printed four lines: a [log] line from the mixin, the SMS line from send, a build call from the mixin class used as a parent (EagerTemplate extends Templated), and log entries: 1. SmsWithLog has one parent, SmsNotifier, and two mixins stacked above it, and an email notifier could take the same two.

Neither a mixin nor a mixin class may have an extends clause or declare a generative constructor (dart.dev/language/mixins). A mixin keeps its own state in the fields it declares.

Dart 3.0 made another rule firm: a plain class may not be used with with. This file tries it and does not compile:

plain_class_fail.dart: a plain class on the right of with Dart · plain_class_fail.dart
// plain_class_fail.dart: a plain class may not be used with `with` since
// Dart 3.0; the declaration must be `mixin` or `mixin class`.
//
// Compile-time error, so this program never runs.

import 'notifier.dart';

class PlainLog {
  void log(String line) {
    print('[log] $line');
  }
}

class Bad extends SmsNotifier with PlainLog {
  Bad(super.sender);
}

void main() {
  Bad('MSCOPL').log('hi');
}

Output (exit status 254)

Printed as an error (standard error)

plain_class_fail.dart:14:36: Error: The class 'PlainLog' can't be used as a mixin because it isn't a mixin class nor a mixin.
class Bad extends SmsNotifier with PlainLog {
                                   ^

Recorded with Dart SDK 3.13.5 (stable) on macos_arm64 on macOS 26 arm64. To run it yourself: dart run plain_class_fail.dart

The compile stopped with “The class ‘PlainLog’ can’t be used as a mixin because it isn’t a mixin class nor a mixin.” Declaring it as mixin class or as mixin fixes it.

Prefer `mixin` when the type is only mixed in

A declaration marked mixin says the design: no code will ever write extends PlainLog. Reach for mixin class only when the same declaration is also used as a parent, as Templated is in mixin_basic.dart.

Checkpoint

Check: Mixins, with and mixin class

  1. Question 1 of 2 What does class SmsWithLog extends SmsNotifier with Log, Templated do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It builds a class with SmsNotifier as its parent, plus every member of Log and Templated

    In mixin_basic.dart, SmsWithLog is one class. It has sender from SmsNotifier, log and logs from Log, and build from Templated, so a single instance can send messages and keep a log at the same time.

  2. Question 2 of 2 plain_class_fail.dart declares class PlainLog and then class Bad extends SmsNotifier with PlainLog. What does Dart 3.13 report?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: A compile error: PlainLog can't be used as a mixin because it isn't a mixin class nor a mixin

    plain_class_fail.dart printed "Error: The class 'PlainLog' can't be used as a mixin because it isn't a mixin class nor a mixin." The fix is to declare PlainLog as mixin class PlainLog or mixin PlainLog.

The on clause opens super and fixes where a mixin applies

A mixin can wrap a method of its host when its on clause names a type every host must be a subtype of. This superclass constraint: A mixin's on T clause: it promises every host of the mixin is a subtype of T, so super calls inside the mixin resolve to T's members at compile time. does two things: it tells the compiler which super calls the mixin may make, and it refuses hosts outside that type. mixin Retry on Notifier can call super.send(to, text) because every host is a Notifier:

retry_super.dart: a Retry mixin that wraps super.send three times Dart · retry_super.dart
// retry_super.dart: a Retry mixin that wraps every send in up to three tries.
// The `on Notifier` clause lets the mixin call `super.send(...)`, which goes
// to the host's own send once this mixin is applied.
//
// Run: dart run retry_super.dart

import 'notifier.dart';

// FlakySms fails its first two attempts, then delivers. The number is fixed
// so the output of this file never changes between runs.
class FlakySms extends SmsNotifier {
  int attempts = 0;
  FlakySms(super.sender);
  @override
  void send(String to, String text) {
    attempts++;
    if (attempts <= 2) {
      throw StateError('gateway timeout on attempt $attempts');
    }
    super.send(to, text);
  }
}

mixin Retry on Notifier {
  int retries = 0;
  @override
  void send(String to, String text) {
    for (var i = 1; i <= 3; i++) {
      try {
        super.send(to, text);
        return;
      } on StateError catch (e) {
        retries++;
        if (i == 3) {
          print('giving up after $i tries: ${e.message}');
          rethrow;
        }
        print('attempt $i failed: ${e.message}; retrying');
      }
    }
  }
}

class RetryingFlakySms extends FlakySms with Retry {
  RetryingFlakySms(super.sender);
}

void main() {
  final s = RetryingFlakySms('MSCOPL');
  s.send('98765 43210', 'Your OTP is 419237.');
  print('retries counted by the mixin: ${s.retries}');
}

Output

attempt 1 failed: gateway timeout on attempt 1; retrying
attempt 2 failed: gateway timeout on attempt 2; retrying
[SMS from MSCOPL] +91 98765 43210: Your OTP is 419237.
retries counted by the mixin: 2

Recorded with Dart SDK 3.13.5 (stable) on macos_arm64 on macOS 26 arm64. To run it yourself: dart run retry_super.dart

The run printed two “attempt N failed” lines, the delivery, and “retries counted by the mixin: 2”. FlakySms fails twice and delivers on the third try, so Retry’s loop runs three times for one send. Without on Notifier, super.send(...) would not compile, and neither would with Retry on a host that is not a Notifier (dart.dev/language/mixins).

A mixin may also declare an abstract member and rely on the host to provide it, in place of the constructor it cannot have. And when two mixins add a member with the same name, Dart linearizes them left to right in the with list, so the mixin written later wins.

Key idea

on T promises every host of the mixin is a subtype of T, so super calls in the mixin resolve to T’s members at compile time, and dispatch at run time follows the host’s chain through to T.

Checkpoint

Check: The on clause and super calls

  1. Question 1 of 2 In retry_super.dart, mixin Retry on Notifier is applied with class RetryingFlakySms extends FlakySms with Retry. What does Retry's super.send(to, text) call?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: FlakySms.send, because FlakySms is the next layer below Retry in the chain

    The recorded run printed "attempt 1 failed", "attempt 2 failed", the real SMS line, and then "retries counted by the mixin: 2". Each super.send landed in FlakySms.send, which threw twice and delivered on the third try.

  2. Question 2 of 2 Why does mixin Retry on Notifier refuse to be mixed in to a class that is not a Notifier?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: on Notifier is a superclass constraint: Retry promises its hosts to be Notifiers, so super.send has a target

    Without on Notifier, the mixin would have no promise about its host and no send to call. The constraint lets Dart check at compile time that every with Retry has a Notifier underneath.

Super chains, same-name members and the four rules a mixin must keep Pro: opens with a Pro, Premium or Ultimate pass

Two mixins in one with list write one chain, and super from each layer steps one slot down it. This part measures the chain with a program that prints before and after every super call, then tests two more rules: when two mixins declare the same member, and when a mixin asks the host for one it does not have. The four rules at the end are the restrictions dart.dev/language/mixins lists.

In this part:

  • How Dart orders super when two mixins share a method
  • Same-name members and the abstract members a mixin asks the host for

2 diagrams · 4 runnable examples (Dart) · about 8 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Choosing between a mixin, a base class and composition, and testing the mixin alone Pro: opens with a Pro, Premium or Ultimate pass

A design can share behaviour three ways: a mixin layered over several hosts, a base class every host extends, and composition that holds a smaller object inside a bigger one. Each one costs the design something, and the right choice depends on which cost the team can pay. This part lines them up with the module’s shared Notifier, then tests a mixin on its own through a tiny host.

In this part:

  • When a mixin fits and when a base class or composition does
  • Testing a mixin through a tiny host

1 runnable example (Dart) · about 6 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: build your own Counting mixin

Write a mixin that counts every outgoing send. Any notifier may be its host, so its on clause names Notifier and nothing more. Start from notifier.dart:

Start from notifier.dart as the base Dart · notifier.dart
// notifier.dart: the shared abstract Notifier and a concrete SmsNotifier.
//
// The mixins lesson reuses the shape from dart/inheritance-and-interfaces: a
// Notifier that promises a single send, and an SmsNotifier that writes it to
// the console in the shop's shape. Nothing in this file is a mixin yet; it is
// the base every example extends.

abstract class Notifier {
  void send(String to, String text);
}

class SmsNotifier extends Notifier {
  final String sender;
  SmsNotifier(this.sender);

  @override
  void send(String to, String text) {
    print('[SMS from $sender] +91 $to: $text');
  }
}
  1. Declare mixin Counting on Notifier with an int sent = 0; field and an @override void send(String to, String text) that increments sent and calls super.send(to, text).
  2. Apply it: class CountingSms extends SmsNotifier with Counting. Build an instance, call send three times, and print s.sent.
  3. Apply the mixin in both orders, with Counting, Log and with Log, Counting, predict which line prints first in each, then run both and compare.
  4. Write a tiny host of your own that drives Counting without the SMS gateway.

When all four steps work, answer the questions below; they begin with your weakest concept:

Practice that adapts to you

Practise this lesson

5 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 5 What does a mixin let you do that a plain class does not, when both have the same methods?

    Choose one answer.

    Show the answer: Question 1 of 5

    Answer: Add those methods to another class with with, without being that class's parent

    mixin_basic.dart added Log and Templated to SmsNotifier without changing its single parent, which is the one thing a plain class could not do.

  2. Question 2 of 5 mixin class Templated is used in mixin_basic.dart as both with Templated and extends Templated. When would you prefer mixin class to mixin?

    Choose one answer.

    Show the answer: Question 2 of 5

    Answer: When the same declaration must sometimes stand alone as a parent and sometimes be mixed in

    EagerTemplate extends Templated, and SmsWithLog applies the same Templated with with; the mixin class declaration keeps the API open for both uses.

  3. Question 3 of 5 A team wants a Templated mixin that takes a greeting in its constructor. no_ctor.dart has Audit(this.limit) and fails to compile. What should the team do?

    Choose one answer.

    Show the answer: Question 3 of 5

    Answer: Drop the constructor and have the host supply the greeting through an abstract getter

    no_ctor.dart printed "Error: Mixins can't declare constructors." The pattern that works is in host_abstract.dart, with String get id; abstract on the mixin and final String id; on the host.

  4. Question 4 of 5 What role does the on clause of a mixin play?

    Choose one answer.

    Show the answer: Question 4 of 5

    Answer: It fixes a superclass constraint, so super calls in the mixin have a known target and only matching hosts may use it

    on Notifier lets Retry call super.send(...), because every host of Retry must be a Notifier, which has a send method the compiler can resolve.

  5. Question 5 of 5 Retry's super.send(to, text) runs the host's send. What happens if a different host extends Notifier directly, so there is no concrete send between Retry and the abstract one?

    Choose one answer.

    Show the answer: Question 5 of 5

    Answer: The program fails to compile, because super.send resolves to an abstract method

    That is why retry_super.dart extends FlakySms, which provides a concrete send; the host plus the chain always reaches a concrete body for every super call.

Interview questions

Warm-up (fresher): In Dart 3, when must a type be declared with mixin or mixin class rather than class?

Any type on the right of with. Since Dart 3.0, a plain class may not be used as a mixin: the declaration must be mixin (only mixed in, never a parent) or mixin class (both at once). The compiler reports “The class ‘C’ can’t be used as a mixin because it isn’t a mixin class nor a mixin.” for the slip, so no program with it will build. A plain class is still fine when it is only ever used with extends or implements; it is only with that needs the newer declaration.

Three longer questions from this module’s bank take mixin design into a real codebase:

  1. Mid to senior

    Four services and three repositories need the same log, metrics and retry behaviour. Draft one is a base class LoggedRetrying the seven extend; draft two is three mixins the seven list in with; draft three is a Pipeline that wraps every call. Which would you ship, and where does each fail first?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Senior to staff

    A payments service uses class Pay extends GatewayBase with Log, Metrics, Retry. A new "verify after retry" check runs twice for every retry, and the team suspects the super chain. Walk through how you would read the order, the measurement you would take to confirm it, and the one-token fix if the chain is wrong.

    Model answer, Pro. First step and follow-ups

  3. Mid to senior

    The team asks why mixin Metrics on Notifier cannot take a MetricsClient in its constructor. Explain what Dart forbids there and show two patterns that keep every host independent: the mixin's own abstract getter, and a static Metrics.of lookup. Say which you would ship and why.

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What is a mixin, and how does a class use one?

    A named block of fields and methods that a class adds with the with keyword, without changing its parent. It suits behaviour that unrelated classes share, such as retries or logging.

  2. How does a mixin class differ from a mixin?

    A mixin class can also stand alone as a parent after extends; a mixin is only ever mixed in. Prefer mixin when the type is only mixed in, since the declaration then says the design.

  3. What happens since Dart 3.0 when a plain class appears after with?

    It does not compile: "can't be used as a mixin because it isn't a mixin class nor a mixin." Declare it mixin or mixin class; a plain class is still fine after extends or implements.

  4. What can neither a mixin nor a mixin class declare?

    An extends clause or a generative constructor. A mixin keeps its own state in the fields it declares, and it may declare an abstract member for the host to provide.

  5. What does the on clause of mixin Retry on Notifier allow?

    super.send(...) inside the mixin, because every host must be a Notifier; with Retry on a class that is not a Notifier does not compile.

  6. Two mixins in one with list add a member with the same name. Which one wins?

    The mixin written later. Dart linearizes the mixins left to right in the with list.

Key takeaways

  • A mixin adds its members to any class that names it with with, and a mixin class is both a mixin and a plain parent; a plain class may not be mixed in since Dart 3.0.
  • An on T clause makes every host a subtype of T, which lets the mixin call super with T’s members.
  • The with list is layered left to right, so the last mixin ends up on top and dispatch starts there.
  • A mixin cannot have a generative constructor; state the mixin needs comes from the host through abstract getters.

Terms in this lesson

mixin
A Dart declaration that adds its members to any class that lists it with the with keyword. A mixin cannot have an extends clause, cannot declare a generative constructor, and may name a superclass constraint with on.
mixin class
A Dart declaration since 3.0 that is both a class (usable with extends) and a mixin (usable with with); it has the same restrictions as a mixin: no extends on itself, no generative constructor.
mixin linearization
Dart's rule for stacking a with list: mixins are layered left to right in the declaration and bottom to top in the chain, so dispatch starts at the last mixin and super steps one slot down.
superclass constraint
A mixin's on T clause: it promises every host of the mixin is a subtype of T, so super calls inside the mixin resolve to T's members at compile time.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.