-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Calling Generic Type Anonymous Functions #3380
Comments
This is a well-known issue. First, there is a workaround: final results =
functions.map((container) => (container as dynamic).function(container.argument)); You used The underlying issue is that you are using a "non-covariant member", that is, a member like With this in mind, we can see that the dynamic type of When we use You can do several things to handle this issue at a more fundamental level. One thing you could do is to change the class class FunctionContainer<T, R> {
final R Function(T) _function;
final T argument;
const FunctionContainer(this._function, this.argument);
R invokeFunction() => _function(argument);
}
void main() {
final Set<FunctionContainer> functions = {
FunctionContainer<String, int>(int.parse, "3"),
FunctionContainer<String, double>(double.parse, "3.141"),
FunctionContainer<String, String>((s) => s, "Hello"),
};
final results =
functions.map((container) => container.invokeFunction());
print(results);
} Another technique you could use would be to change However, this wouldn't fit your use case so well because you want to store functions with different parameter types in the same set, and that's inherently unsafe. If you change |
I'll close this issue because it's all described in other issues as mentioned. |
@LeoBound, I'd like to add another comment on this issue, because of the narrow scope of the proposed solution. It is indeed true that replacing So let's generalize slightly and consider the situation where we have a list of arguments, and we'd like to pick and choose the arguments from that list and pass them as actual arguments to the function. We can do this be "opening" each import 'package:typer/typer.dart';
class FunctionContainer<T, R> {
final R Function(T) _function;
final List<T> arguments;
const FunctionContainer(this._function, this.arguments);
R function(T argument) => _function(argument);
Typer<R> get typerOfR => Typer();
}
String listTypes(List<Object?> list) {
var buffer = StringBuffer('[');
buffer.write(list.map((r) => '${r.runtimeType}').join(', '));
buffer.write(']');
return buffer.toString();
}
void main() {
final Set<FunctionContainer<String, Object>> functions = {
FunctionContainer<String, int>(int.parse, ["3", "4"]),
FunctionContainer<String, double>(double.parse, ["3.141", "2.7181"]),
FunctionContainer<String, String>((s) => s, ["Hello", "world!"]),
};
final results =
functions.map((container) {
var typer = container.typerOfR;
return typer.callWith<List<Object?>>(<R>() {
// Inform the type system about guaranteed typings.
var containerR = container as FunctionContainer<String, R>;
var result = <R>[];
for (var argument in containerR.arguments) {
result.add(containerR.function(argument));
}
return result;
});
}).toList();
print('Values: $results');
print('Types: ${listTypes(results)}');
}
// NB: The explicit type argument to `callWith` is only needed because of
// https://github.com/dart-lang/sdk/issues/55644. In the invocation of This shows that you need more machinery in order to be able to work safely with a class like |
@eernstg Thanks for the update. I've actually been trying to solve a similar scenario recently in a different project and this has solved it 🙂 I wasn't aware of the typer package but it looks helpful! |
Is it possible to do something like the following?
I would expect the result to be a List<dynamic> containing [3, 4.141, "Hello"], and statically the compiler doesn't detect any issues with the code.
Instead I get
TypeError: Closure 'int_parse': type '(String, {((String) => int)? onError, int? radix}) => int' is not a subtype of type '(dynamic) => dynamic'
at runtime.Although the example above doesn't seem hugely motivated, I would like to use a similar pattern to create JSON (Map<String, dynamic>) from some form fields.
Is there a workaround for this?
Thanks
The text was updated successfully, but these errors were encountered: