Dart unfortunately lacks (by design) the ability to specify invariant or contravariant type parameters. So when I need them, how do I work around their absence?
Take the abstract setting of a Producer<T>
and a Consumer<T>
class.
abstract class Producer<T> {
T produce();
}
abstract class Consumer<T> {
void consume(T item);
}
The type parameter in Producer
should be covariant, but in Consumer
it should be contravariant (a concrete example: method parameters are contravariant, return types are covariant). However, Dart will automatically make the type parameter in Consumer
covariant, without a way of specifying otherwise.
So if some other code component needs, for example, a Consumer<num>
, conceptually it should accept a Consumer<Object>
, because if a consumer accepts any object, it will certainly accept an number. But if I just write:
void someFunction(Consumer<num> consumer);
This will accept only Consumer<num>
or Consumer<int>
, Consumer<float>
etc. which will cause errors.
So how should I write it instead? Some options that occurred to me:
void someFunction(Consumer<dynamic> consumer);
This removes static type checking, which I don't want.
There is no workaround, generics are currently covariant. The best you can do is either:
If the only thing the Consumer
class does is to consume
, it's a single-method interface, and you can just use a function type, and pass around function values, instead.