Dart Bounded Generics
A bound limits the types a type parameter can accept. The bound is written with extends right after the type parameter.
A total for numbers only
Total accepts a list of one number type. Its sum method adds the values with +.
class Total<T extends num> {
final List<T> values;
Total(this.values);
num sum() {
num total = 0;
for (var value in values) {
total = total + value;
}
return total;
}
}
void main() {
print(Total<int>([10, 20]).sum());
print(Total<double>([1.5, 2.25]).sum());
}A bound on a function
bigger carries the bound on its own type parameter. It compares two values of the same number type.
T bigger<T extends num>(T a, T b) {
if (a > b) {
return a;
}
return b;
}
void main() {
print(bigger(3, 8));
print(bigger(4.5, 1.5));
}A bound that names a class
The bound names the class Named. describe can call label on any value of type T.
class Named {
final String name;
Named(this.name);
String label() {
return name;
}
}
class Dish extends Named {
Dish(String name) : super(name);
}
String describe<T extends Named>(T item) {
return item.label();
}
void main() {
print(describe(Dish('Pasta')));
print(describe(Dish('Rice')));
}Breaking the bound
String is not a subtype of num. The compiler rejects the program before it can run.
class Total<T extends num> {
final List<T> values;
Total(this.values);
num sum() {
num total = 0;
for (var value in values) {
total = total + value;
}
return total;
}
}
void main() {
var bad = Total<String>(['a', 'b']);
print(bad.sum());
}Example
class Total<T extends num> {
final List<T> values;
Total(this.values);
num sum() {
num total = 0;
for (var value in values) {
total = total + value;
}
return total;
}
}
void main() {
var ints = Total<int>([5, 15, 40]);
var doubles = Total<double>([2.5, 7.5]);
print('Total: ${ints.sum()}');
print('Total: ${doubles.sum()}');
}Key points
- A bound in a class reads class Total<T extends num>.
- Only num and its subtypes int and double can fill a num bound.
- Inside the class, a value of type T can use the num operations, such as +.
- A generic function can carry a bound too.
- A bound can name a plain class, and the code can then call methods of that class on values of type T.
In this example, one Total holds ints and sums to 60. The other holds doubles and sums to 10.0. The same class serves both number types because the bound admits both.
Note
a type that breaks the bound fails at compile time, before the program runs.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท DartPad
Exercise
Which type can fill T in class Total<T extends num>?