Skip to content

Commit 3a0eca8

Browse files
committed
rewrite mixin page
1 parent b0a828d commit 3a0eca8

File tree

1 file changed

+100
-49
lines changed

1 file changed

+100
-49
lines changed

src/content/language/mixins.md

+100-49
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ Mixins are a way of defining code that can be reused in multiple class hierarchi
1616
They are intended to provide member implementations en masse.
1717

1818
To use a mixin, use the `with` keyword followed by one or more mixin
19-
names. The following example shows two classes that use mixins:
19+
names. The following example shows two classes that use (or, are subclasses of)
20+
mixins:
2021

2122
<?code-excerpt "misc/lib/language_tour/classes/orchestra.dart (musician-and-maestro)" replace="/(with.*) \{/[!$1!] {/g"?>
2223
```dart
@@ -60,29 +61,104 @@ mixin Musical {
6061
}
6162
```
6263

63-
Sometimes you might want to restrict the types that can use a mixin.
64-
For example, the mixin might depend on being able to invoke a method
65-
that the mixin doesn't define.
66-
As the following example shows, you can restrict a mixin's use
67-
by using the `on` keyword to specify the required superclass:
64+
## Specify members a mixin can call on itself
65+
66+
Sometimes a mixin depends on being able to invoke a method or access fields,
67+
but can't define those members itself (because mixins can't use constructor
68+
parameters to instantiate their own fields).
69+
70+
The following sections cover different strategies for ensuring any subclass
71+
of a mixin defines any members the mixin's behavior depends on.
72+
73+
### Define abstract members in the mixin
74+
75+
By declaring the mixin as abstract, you force any type that uses
76+
it to define the abstract method upon which its behavior depends.
77+
78+
```dart
79+
abstract mixin Musician {
80+
void playInstrument(String instrumentName); // Abstract method.
81+
82+
void playPiano() {
83+
playInstrument('Piano');
84+
}
85+
void playFlute() {
86+
playInstrument('Flute');
87+
}
88+
}
89+
90+
class Virtuoso with Musician {
91+
void playInstrument(String instrumentName) { // Subclass must define.
92+
print('Plays the $instrumentName beautifully');
93+
}
94+
}
95+
```
96+
97+
#### Access state in the mixin's subclass
98+
99+
Declaring abstract memebers also allows you to access state on the subclass
100+
of a mixin, by calling getters which are defined as abstract on the mixin:
101+
102+
```dart
103+
/// Can be applied to any type with a [name] property and provides an
104+
/// implementation of [hashCode] and operator `==` in terms of it.
105+
mixin NameIdentity {
106+
String get name;
107+
108+
int get hashCode => name.hashCode;
109+
bool operator ==(other) => other is NameIdentity && name == other.name;
110+
}
111+
112+
class Person with NameIdentity {
113+
final String name;
114+
115+
Person(this.name);
116+
}
117+
```
118+
119+
### Implement an interface
120+
121+
Similar to declaring the mixin abstract, putting an `implements` clause on the
122+
mixin while not actually implementing the interface will also ensure any member
123+
dependencies are defined for the mixin.
124+
125+
```dart
126+
?
127+
```
128+
129+
### Use the `on` clause to declare a superclass
130+
131+
The `on` clause exists to define the type that `super` calls are resolved against.
132+
So, you should only use it if you need to have a `super` call inside a mixin.
133+
134+
The `on` clause forces any class that uses a mixin to also be a subclass
135+
of the type in the `on` clause.
136+
If the mixin depends on members in the superclass,
137+
this ensures those members are available where the mixin is used:
68138

69139
<?code-excerpt "misc/lib/language_tour/classes/orchestra.dart (mixin-on)" plaster="none" replace="/on Musician2/[!on Musician!]/g" ?>
70140
```dart
71141
class Musician {
72-
// ...
142+
musicianMethod() {
143+
print('Playing music!');
144+
}
73145
}
74146
mixin MusicalPerformer [!on Musician!] {
75-
// ...
147+
perfomerMethod() {
148+
print('Performing music!');
149+
super.musicianMethod();
150+
}
76151
}
77-
class SingerDancer extends Musician with MusicalPerformer {
78-
// ...
152+
153+
class SingerDancer extends Musician with MusicalPerformer { }
154+
155+
main() {
156+
SingerDance().performerMethod();
79157
}
80158
```
81159

82-
In the preceding code,
83-
only classes that extend or implement the `Musician` class
84-
can use the mixin `MusicalPerformer`.
85-
Because `SingerDancer` extends `Musician`,
160+
In this example, only classes that extend or implement the `Musician` class
161+
can use the mixin `MusicalPerformer`. Because `SingerDancer` extends `Musician`,
86162
`SingerDancer` can mix in `MusicalPerformer`.
87163

88164
## `class`, `mixin`, or `mixin class`?
@@ -95,49 +171,24 @@ A `mixin` declaration defines a mixin. A `class` declaration defines a [class][]
95171
A `mixin class` declaration defines a class that is usable as both a regular class
96172
and a mixin, with the same name and the same type.
97173

98-
Any restrictions that apply to classes or mixins also apply to mixin classes:
99-
100-
- Mixins can't have `extends` or `with` clauses, so neither can a `mixin class`.
101-
- Classes can't have an `on` clause, so neither can a `mixin class`.
102-
103-
### `abstract mixin class`
104-
105-
You can achieve similar behavior to the `on` directive for a mixin class.
106-
Make the mixin class `abstract` and define the abstract methods its behavior
107-
depends on:
108-
109174
```dart
110-
abstract mixin class Musician {
111-
// No 'on' clause, but an abstract method that other types must define if
112-
// they want to use (mix in or extend) Musician:
113-
void playInstrument(String instrumentName);
114-
115-
void playPiano() {
116-
playInstrument('Piano');
117-
}
118-
void playFlute() {
119-
playInstrument('Flute');
120-
}
175+
mixin class Musician {
176+
// ...
121177
}
122178
123-
class Virtuoso with Musician { // Use Musician as a mixin
124-
void playInstrument(String instrumentName) {
125-
print('Plays the $instrumentName beautifully');
126-
}
127-
}
179+
class Novice with Musician { // Use Musician as a mixin
180+
// ...
181+
}
128182
129183
class Novice extends Musician { // Use Musician as a class
130-
void playInstrument(String instrumentName) {
131-
print('Plays the $instrumentName poorly');
132-
}
133-
}
184+
// ...
185+
}
134186
```
135187

136-
By declaring the `Musician` mixin as abstract, you force any type that uses
137-
it to define the abstract method upon which its behavior depends.
188+
Any restrictions that apply to classes or mixins also apply to mixin classes:
138189

139-
This is similar to how the `on` directive ensures a mixin has access to any
140-
interfaces it depends on by specifying the superclass of that interface.
190+
- Mixins can't have `extends` or `with` clauses, so neither can a `mixin class`.
191+
- Classes can't have an `on` clause, so neither can a `mixin class`.
141192

142193
[language version]: /guides/language/evolution#language-versioning
143194
[class]: /language/classes

0 commit comments

Comments
 (0)