DART / CHAPTER 05
Generic contracts and runtime element checks
IntermediatePreserve type relationships while respecting collection variance.
By the end of this chapter
- Write a type-preserving helper
- Bound a generic parameter by required behavior
- Distinguish static views from runtime list element types
The idea
A generic function connects related input and output types. A helper taking List<T> can return a T without discarding whether its elements are strings, numbers, or domain objects. Bounds express capabilities required by the implementation. Avoid replacing a meaningful type relationship with dynamic simply because several concrete types should be supported.
Dart retains generic type information at runtime. Its covariant collection relationships can allow a narrower list to be viewed through a broader element type, but writes still face runtime checks against the actual list type. A List<int> does not become a list capable of storing every num merely because a reference is typed List<num>. Prefer read-only behavior or a fresh appropriately typed collection when widening a mutable API.
T first<T>(List<T> values) {
if (values.isEmpty) throw StateError("empty");
return values.first;
}
void main() { print(first<String>(["a","b"])); }a
The type parameter connects the element type to the result type. Empty input is explicitly outside this helper’s successful contract.
Try it yourself
Write a generic helper returning the last value or a supplied fallback for an empty list.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING