Closed vsmenon closed 2 years ago
When tearing off the constructor of a generic class, the function tear-off is always instantiated so the resulting function is not generic. This works the same way as instantiated tear-off of any other function, except that it is not an option to not instantiate when tearing off. If type inference has no constraints on the type arguments, they will be filled in by instantiate to bounds.
@lrhn Just so I understand:
class Foo<T> {
T field;
Foo(this.field);
Foo.named<E>(List<E> list, this.field);
}
var a = Foo.new; // Foo<dynamic> Function(dynamic)
var b = Foo.named; // Foo<dynamic> Function(List<dynamic>, dynamic)
var c = Foo<int>.new; // error?
var d = Foo.named<int>; // error?
If so, how about this instead:
var a = Foo.new; // Foo<dynamic> Function(dynamic)
var b = Foo.named; // Foo<dynamic> Function(List<dynamic>, dynamic)
var c = Foo<int>.new; // Foo<int> Function(int)
var d = Foo<int>.named; // Foo<int> Function(List<dynamic>, int)
var e = Foo<int>.named<String>; // Foo<int> Function(List<String>, int)
Maybe you misunderstood the example. In Map<K, V>
, K
is for the keys and V
is for the values. The E
in Map.fromIterable<E>
would mean that instead of passing in an Iterable
, you pass an Iterable<E>
. Currently, there is no E
and thus it's automatically Iterable<dynamic>
. In other words, even if the user passes in a List<int>
, the functions don't know that and expect a dynamic
parameter:
final Map<String, int> map = Map.fromIterable(
[0, 1, 2], // clearly an Iterable<int>, but...
// ERROR: String Function(int) cannot be assigned to String Function(dynamic)
key: (int index) => index.toString(),
// ERROR: int Function(int) cannot be assigned to int Function(dynamic)
value: (int index) => index + 1
);
Changing both index
parameters to dynamic
fixes the issue, but it's weird (and unsafe) that Dart forces you to use dynamic
instead of actual types here. As I said in my earlier comment, we can fix this by simply introducing an E
type argument:
Map.fromIterable(Iterable iterable, K key(element), V value(element)); // current Map.fromIterable<E>(Iterable<E> iterable, K key(E element), V value(E element)); // new
So now the example becomes:
final Map<String, int> map = Map.fromIterable<int>( [0, 1, 2], // Iterable<int> key: (int index) => index.toString(), // String Function(int) value: (int index) => index + 1 // int Function(int) );
Based on this, point of generic constructors is to sync up the types of the parameters, just like regular functions can.
@Levi-Lesches Yes. Whether to allow the explicitly specified type arguments in tear-offs is an open question. I started out with a proposal without it, to keep the proposal small, but if it can be included, then I'm all for it (#123).
@mit-mit – is this done? Just waiting for release to close?
Released in the last beta, shipping in the upcoming 2.15 stable.
Support tearing-off and passing constructors similar to current support for functions. Example:
Language proposal: https://github.com/dart-lang/language/blob/master/accepted/2.15/constructor-tearoffs/feature-specification.md
Original issue filed by @rhcarvalho on February 11, 2019 10:59 as dart-lang/sdk#35901
This feature request intends to allow using constructors where functions with the same type/signature are expected.
Example code: https://dartpad.dartlang.org/9745b0f73157959a1c82a66ddf8fdba4
Background
As of Dart 2, Effective Dart suggests not using the
new
keyword and removing it from existing code. Doing that makes named constructors and static methods look the same at call sites.The Language Tour says (emphasis mine):
Thus suggesting that a constructor is a function. But it turns out it is not really a function, as it cannot be used in all contexts where a function can.
Why it would be useful
Dart built in types, in particular collection types, have several methods that take functions as arguments, for instance
.forEach
and.map
, two concise and expressive ways to perform computations.In an program I'm working on, I got a bit surprised by not being able to create new instances using
Iterable.map
+ a named constructor. And then I realized that others have arrived at the same conclusion at least 4 years back on StackOverflow, but I could not find a matching issue.Example Flutter code
What I would like to write:
What I have to write instead with Dart 2.1.0:
Note that the feature request is not specific to Flutter code, but applies to any Dart code as per the more generic example in https://dartpad.dartlang.org/9745b0f73157959a1c82a66ddf8fdba4.