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();