Mobile Development 24 min read

Dart Generics: Covariance, Contravariance, and Type Safety

This article explains Dart's generic type system, comparing its covariance, contravariance, and invariance with Java and Kotlin, demonstrates practical code examples, discusses safety concerns of mutable covariant collections, and introduces the 'covariant' keyword for safe method overriding in Flutter development.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Dart Generics: Covariance, Contravariance, and Type Safety

Dart supports generics similar to Java and Kotlin, but its handling of covariance, contravariance, and invariance differs. In Dart, generic classes are covariant by default, allowing a List<Girl> to be used where a List<Person> is expected. This simplifies code reuse but introduces safety risks because the collections remain mutable.

The article provides concrete examples: a generic PrintMsg<T>(T value) function, usage of List<int> versus List<dynamic> , and how type inference works when generic parameters are omitted. It also contrasts Dart's runtime type retention with Java/Kotlin's type erasure, showing that Dart can perform type checks like value is List<String> at runtime.

Covariance and contravariance are explained using Java's ArrayList<? extends Number> and ArrayList<? super Number> syntax, and the PECS principle (Producer‑Extends, Consumer‑Super) is introduced. The article demonstrates how these concepts enable safe polymorphic behavior in collections, such as adding a List<Boy> to a List<Person> via addAll , and using forEach with a Consumer<? super Person> .

In Dart, because generic collections are both covariant and mutable, writing to a covariant collection can cause runtime type errors. The article shows a problematic case where a PrintMsg(List<Person> persons) function receives a List<Girl> and attempts to add a Boy , leading to a type mismatch.

To mitigate such issues, Dart introduces the covariant keyword, allowing overridden methods to narrow parameter types safely. Examples include BoyHouse and GirlHouse classes that override a checkin method with covariant Boy or covariant Girl parameters, preventing inappropriate objects from being passed.

The article also highlights real‑world Flutter usage, such as passing a List<ElevatedButton> to a function expecting List<Widget> , and shows how the covariant keyword is applied in the project's state management classes to enforce type safety.

Overall, the piece emphasizes understanding generic variance, applying the PECS principle, and using Dart's covariant modifier to write safer, more maintainable mobile code.

dartfluttergenericstype safetycovarianceContravariance
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.