Mixins

Linearization: class C extends A with M1, M2 creates the chain A → A+M1 → A+M1+M2 → C. Later mixins override earlier ones. super calls go up that chain.

Mixins can't have generative constructors. Use them for reusable behavior (logging, serialization helpers, Flutter's TickerProviderStateMixin).

mixin Logging {
  void log(String message) => print('[${runtimeType}] $message');
}

mixin Timestamped {
  DateTime? _updatedAt;
  void touch() => _updatedAt = DateTime.now();
  DateTime? get updatedAt => _updatedAt;
}

mixin Validatable on Model {              // `on`: only usable by subclasses of Model (and can call its members)
  bool validate() => fields.values.every((v) => v != null);
}

abstract class Model {
  Map<String, Object?> get fields;
}

class User extends Model with Logging, Timestamped, Validatable {
  String? name;
  @override
  Map<String, Object?> get fields => {'name': name};
}

void main() {
  final u = User()..name = 'Ana';
  u.touch();
  u.log('validated: ${u.validate()}');
}

mixin class Musician {                    // Dart 3: usable both as a class and as a mixin
  void play() => print('Playing music');
}
class Pianist with Musician {}
final m = Musician();