I'm trying to define a callback function that needs to accept a generic parameter and return a value of the same type. Keep in mind that the following example is an oversimplified version of what I actually need.
final T Function<T>(T value) self = (value) => value
This results in the following error, that I can't seem to get rid of.
The argument type '(dynamic) → dynamic' can't be assigned to the parameter type '<T>(T) → T'
dart(argument_type_not_assignable)
The only thing that seems to work is to give the value a type, but that defeats the purpose of using a type parameter in the first place.
final T Function<T>(T value) same = <String>(value) => value;
I need it to be generic so that the caller can pass the type it expects in return. I also need it to be stored in a variable, so I can pass it around as a callback function.
If this isn't directly possible, do you know of any workarounds? Thank you in advance.
Here's a more complete example if the requirements aren't clear.
abstract class Provider<T> {
T get bar;
}
class StringProvider extends Provider<String> {
String get bar => 'bar';
}
class NumberProvider extends Provider<int> {
int get bar => 42;
}
class Foo {
final T Function<T>(Provider<T> provider) provide;
const Foo({ this.provide });
}
test() {
final foo = Foo(provide: (provider) => provider.bar);
String strValue = foo.provide(StringProvider()); // should be 'bar'
int numValue = foo.provide(NumberProvider()); // should be 42
}
The annoying thing is that Dart actually understands that foo.provide(StringProvider()) will return a string and that using NumberProvider will indeed return an integer, and yet, the error is still risen for the line where the variable is actually given a value.
final foo = Foo(provide: (provider) => provider.bar);
The argument type '(dynamic) → dynamic' can't be assigned to the parameter type '<T>(Provider<T>) → T'
It turns out that I can cheat the type checker by giving any concrete type when defining the value. Note that
dynamicis not allowed, but anything else goes.This both gets rid of the error and allows for the
providemethod to return the correct type when called.In conclusion, this seems like a simple shortcoming of the type checker, not something that's actually impossible or difficult to achieve using the already existing language features. I will be raising an issue on the language's GitHub repository to allow for further investigation and discussion.
Update #1: the issue has been opened on GitHub.
Update #2: the issue has been resolved, and it turns out that the behavior is by design. Quoting Erik Ernst from the SDK team:
It turns out that simply adding
<T>before the parameter list (instead ofintas in the original workaround) solved the issue.This forces Dart to understand that provider is of type
Provider<T>and that the method will return a value of typeT, saving us from using a concrete type and still getting rid of the error.