I checked all my generics are all OK. Inheritance seems ok. Type inference seems ok. No compiler error. I don't have any hard type casting. Everything is seems strongly typed.
class ModelField {}
class DropdownField<V> extends ModelField {
final void Function(V value) setValue;
final List<V> options;
DropdownField({
required this.setValue,
required this.options,
});
}
void _buildDropdownField<V>(DropdownField<V> field) {
final options = field.options;
final data = options.first;
field.setValue(data); // error Here
}
void _renderField(ModelField field) {
/// from server
// if field is StringField, else if field is DateField, ... else
if (field is DropdownField<Object>) {
// print('field is DropdownField<dynamic, dynamic>');
_buildDropdownField(field);
}
}
void main() {
final field =
DropdownField<int>(setValue: (value) => print(value), options: [1, 2, 3]);
_renderField(field);
}
But when I run:
Unhandled exception:
type '(int) => void' is not a subtype of type '(Object) => void'
#0 _buildDropdownField (package:shared_core/weird_dart/generic_promotion.dart:18:9)
#1 _renderField (package:shared_core/weird_dart/generic_promotion.dart:26:5)
#2 main (package:shared_core/weird_dart/generic_promotion.dart:34:3)
#3 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#4 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
How can int
not be a subtype of Object
???
I am so confused (or Dart is) I hope it's me. But this error occurs only at run time.
The proper solution I found is to give the compiler "more clues" about the Sound Variance. Hence use the keyword inout
Thus: class DropdownField<inout V>
. What the inout
keyword means
“Hey, compiler, V in DropdownField is gonna both take values in and give them out. V is in when we pass it to setValue, and it’s out when we get values from options. So don’t stress—it’s all good for both directions!”
Note:
This still an experimental flag.
environment:
sdk: '>=3.4.3 <4.0.0'
And add the experimental flag. --enable-experiment=variance
class ModelField {}
class DropdownField<inout V> extends ModelField {
final void Function(V value) setValue;
final List<V> options;
DropdownField({
required this.setValue,
required this.options,
});
}
void _buildDropdownField<V>(DropdownField<V> field) {
final options = field.options;
final data = options.first;
print(field.setValue);
field.setValue(data);
}
void _renderField(ModelField field) {
/// from server
// if field is StringField, else if field is DateField, ... else
if (field is DropdownField<Object>) {
// print('field is DropdownField<dynamic, dynamic>');
_buildDropdownField(field);
}
}
void main() {
final field =
DropdownField<int>(setValue: (value) => print(value), options: [1, 2, 3]);
_renderField(field);
}