DMarlon Studio

Lesson 6 · 6 of 20

Mixins · Dart

Reuse behaviour in Dart with mixins: with to apply them, on to restrict them and abstract members that ask the class for data.

Dart · Mixins in DMarlon Studio: the example's code and its output in the terminal

Dart only lets a class extend one other class, yet several unrelated classes often need the same piece of behaviour. A `mixin` is that reusable piece: fields and methods that are mixed into a class with the `with` keyword.

Discountable adds a field, percentOff, and a getter, finalPrice, which takes off the percentage using integer division. `on Product` restricts it to classes that are a Product and, in exchange, it can safely use price: the compiler knows it will be there.

Shippable has no restriction and declares weightKg as abstract: the class that uses it must provide it. With that value it computes shippingCost, 399 cents up to one kilo and 699 above that. So a mixin can offer logic and, in return, demand the data it needs.

Book mixes in both (with Discountable, Shippable) and Ebook only the discount, because a digital book is never shipped. In main, the cascade ..percentOff = 20 sets the field the mixin brought along. Mixins are types too, and is recognises them: a Book is Discountable as well as a Product, while an Ebook is not Shippable.

Code · main.dart

abstract class Product { String get name; int get price; } // price in cents// A mixin adds fields and methods to any class that uses it.// "on Product" means it can only be mixed into products.mixin Discountable on Product {  int percentOff = 0;  int get finalPrice => price - price * percentOff ~/ 100;}mixin Shippable {  double get weightKg; // the class must provide this  int get shippingCost => weightKg <= 1 ? 399 : 699;}class Book extends Product with Discountable, Shippable {  @override final String name = 'Clean Code';  @override final int price = 3500;  @override final double weightKg = 0.8;}class Ebook extends Product with Discountable {  @override final String name = 'Dart in Action (PDF)';  @override final int price = 1800;}void main() {  final book = Book()..percentOff = 20;  final ebook = Ebook()..percentOff = 50;  print('${book.name}: ${book.finalPrice} + shipping ${book.shippingCost}');  print('${ebook.name}: ${ebook.finalPrice}, ships: ${ebook is Shippable}');  print('A Book is Discountable: ${book is Discountable}, is Product: ${book is Product}');}

Output · dart run main.dart

Clean Code: 2800 + shipping 399
Dart in Action (PDF): 900, ships: false
A Book is Discountable: true, is Product: true

Key points

  • A mixin reuses code across classes that share no inheritance.
  • Apply it with with; several can be applied at once.
  • on Class restricts where it can be used and gives access to that class's members.
  • A mixin can require abstract members from the class using it.
  • Mixins are types too: they work with is.

Exercise

Create a Reviewable mixin with a list of scores and a rating getter that returns their average, apply it to Book and add two reviews.