What are Generics?
Generics allow you to write code that works with multiple types while remaining type-safe. Instead of writing separate classes for List<int> and List<String>, one generic List<T> handles both.
Why Use Generics?
- Type safety: Catches type errors at compile time
- Code reuse: One implementation works for many types
- No casting: Avoids unsafe dynamic casts
Generic Classes
class Box<T> {
T value;
Box(this.value);
T getValue() => value;
void setValue(T newValue) { value = newValue; }
@override
String toString() => 'Box<$T>($value)';
}
void main() {
var intBox = Box<int>(42);
var strBox = Box<String>('Hello');
var dblBox = Box<double>(3.14);
print(intBox); // Box<int>(42)
print(strBox); // Box<String>(Hello)
print(dblBox); // Box<double>(3.14)
intBox.setValue(100);
print(intBox.getValue() + 1); // 101
}
Generic Functions
T first<T>(List<T> list) => list.first;
T last<T>(List<T> list) => list.last;
Pair<A, B> makePair<A, B>(A first, B second) => Pair(first, second);
class Pair<A, B> {
A first;
B second;
Pair(this.first, this.second);
@override String toString() => '($first, $second)';
}
void main() {
print(first([1, 2, 3])); // 1
print(last(['a', 'b', 'c'])); // c
print(makePair('key', 42)); // (key, 42)
}
Type Constraints
Use extends to restrict which types can be used with a generic:
// Only numeric types
T sum<T extends num>(List<T> values) {
return values.reduce((a, b) => (a + b) as T);
}
print(sum([1, 2, 3, 4])); // 10
print(sum([1.1, 2.2, 3.3])); // 6.6
// sum(['a', 'b']); ← COMPILE ERROR
Example: Generic Stack
class Stack<T> {
final List<T> _items = [];
void push(T item) => _items.add(item);
T pop() => _items.removeLast();
T get peek => _items.last;
bool get isEmpty => _items.isEmpty;
int get size => _items.length;
}
void main() {
var stack = Stack<int>();
stack.push(1); stack.push(2); stack.push(3);
print(stack.peek); // 3
print(stack.pop()); // 3
print(stack.size); // 2
}
🧠 Quiz
1. What does <T> represent in a generic class?
- A) A template literal
- B) A type parameter that is specified when using the class ✅
- C) A type check
- D) A generic interface
2. What does <T extends num> do?
- A) T must be exactly num
- B) T must be a subtype of num ✅
- C) T extends the num class
- D) T is optional
Summary
Generics write type-safe, reusable code with type parameters (<T>). Generic classes and functions work with any type while preserving type information. Use T extends Type to constrain which types are allowed. Built-in types like List<T>, Map<K, V>, and Set<T> are all generic.