Mixins
Mixins are a way of defining code that can be reused in multiple class hierarchies. They are intended to provide member implementations en masse.
To use a mixin, use the with
keyword followed by one or more mixin names. The following example shows two classes that use (or, are subclasses of) mixins:
class Musician extends Performer with Musical {
// ยทยทยท
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
To define a mixin, use the mixin
declaration. In the rare case where you need to define both a mixin and a class, you can use the mixin class
declaration.
Mixins and mixin classes cannot have an extends
clause, and must not declare any generative constructors.
For example:
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
Specify members a mixin can call on itself
#Sometimes a mixin depends on being able to invoke a method or access fields, but can't define those members itself (because mixins can't use constructor parameters to instantiate their own fields).
The following sections cover different strategies for ensuring any subclass of a mixin defines any members the mixin's behavior depends on.
Define abstract members in the mixin
#Declaring an abstract method in a mixin forces any type that uses the mixin to define the abstract method upon which its behavior depends.
mixin Musician {
void playInstrument(String instrumentName); // Abstract method.
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
class Virtuoso with Musician {
void playInstrument(String instrumentName) { // Subclass must define.
print('Plays the $instrumentName beautifully');
}
}
Access state in the mixin's subclass
#Declaring abstract members also allows you to access state on the subclass of a mixin, by calling getters which are defined as abstract on the mixin:
/// Can be applied to any type with a [name] property and provides an
/// implementation of [hashCode] and operator `==` in terms of it.
mixin NameIdentity {
String get name;
int get hashCode => name.hashCode;
bool operator ==(other) => other is NameIdentity && name == other.name;
}
class Person with NameIdentity {
final String name;
Person(this.name);
}
Implement an interface
#Similar to declaring the mixin abstract, putting an implements
clause on the mixin while not actually implementing the interface will also ensure any member dependencies are defined for the mixin.
abstract interface class Tuner {
void tuneInstrument();
}
mixin Guitarist implements Tuner {
void playSong() {
tuneInstrument();
print('Strums guitar majestically.');
}
}
class PunkRocker with Guitarist {
void tuneInstrument() {
print("Don't bother, being out of tune is punk rock.");
}
}
Use the on
clause to declare a superclass
#The on
clause exists to define the type that super
calls are resolved against. So, you should only use it if you need to have a super
call inside a mixin.
The on
clause forces any class that uses a mixin to also be a subclass of the type in the on
clause. If the mixin depends on members in the superclass, this ensures those members are available where the mixin is used:
class Musician {
musicianMethod() {
print('Playing music!');
}
}
mixin MusicalPerformer on Musician {
performerMethod() {
print('Performing music!');
super.musicianMethod();
}
}
class SingerDancer extends Musician with MusicalPerformer { }
main() {
SingerDancer().performerMethod();
}
In this example, only classes that extend or implement the Musician
class can use the mixin MusicalPerformer
. Because SingerDancer
extends Musician
, SingerDancer
can mix in MusicalPerformer
.
class
, mixin
, or mixin class
?
#A mixin
declaration defines a mixin. A class
declaration defines a class. A mixin class
declaration defines a class that is usable as both a regular class and a mixin, with the same name and the same type.
mixin class Musician {
// ...
}
class Novice with Musician { // Use Musician as a mixin
// ...
}
class Novice extends Musician { // Use Musician as a class
// ...
}
Any restrictions that apply to classes or mixins also apply to mixin classes:
- Mixins can't have
extends
orwith
clauses, so neither can amixin class
. - Classes can't have an
on
clause, so neither can amixin class
.
Unless stated otherwise, the documentation on this site reflects Dart 3.5.4. Page last updated on 2024-10-22. View source or report an issue.