-
Notifications
You must be signed in to change notification settings - Fork 207
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
please extend for-in syntax to maps #2183
Comments
I don't think we'll do this until we have patters or records (current proposals: https://github.com/dart-lang/language/blob/master/working/0546-patterns/patterns-feature-specification.md, https://github.com/dart-lang/language/blob/master/working/0546-patterns/records-feature-specification.md). At that point, we could possibly allow pattern matches in the binding of the for (var (key: k, value: v) in map.entries) { ... } where With views, we could even make @munificent |
@lrhn thanks for the links. great to see destructuring in the works. while i realize destructuring may allow syntax like for (var (key: k, value: v) in map.entries) { ... } it's very noisy compared to the proposal. maps are one of the most common data structures, { for (var x in xs) x: f(x) } the expression <X, Y>{ for (var x in xs) MapEntry(x, f(x)) } btw, currently for-in loops don't allow declaring > 1 loop control variable: for (var x, y in xs) {} // syntax error: unexpected token ','
var x, y; // allowed so i don't think the proposal has any conflict with existing syntax. in terms of intuition, if someone wanted to iterate over for k, v in map.items():
print(k, v) but it still forces you to say |
It's definitely possible to introduce a special Whether it's worth the extra complexity over just iterating the entries directly, is what we'll have to decide. |
indeed a simple |
If |
@Jetz72 If this new loop for maps got added you could do: for (var index, element in someList.asMap()) {
print('$index: $element');
} |
Yes, the patterns proposal does support using patterns in for-in variable declarations. The exact syntax you have up there would work. As would the slightly shorter: for (var (key:, value:) in map.entries) {
// Local variables "key" and "value" here...
} Having to extract the key and value by name is a drag, as is having to call
Personally, I'd lean towards 3. |
@munificent Would that mean that we would be able to implement |
We can't make We don't currently have an interface that only contains I do not like If we had had records when It probably would have been named if other people had a say, a lot of people seem to like being explicit over being brief. I'd go for positional myself. The name isn't needed, and if you're ever in doubt whether it's (key, value) or (value, key), ... well, you won't be, or the types will set you straight. (Could we have "optionally named positional record entries"? Say |
I'd vote for non-named arguments, because Non-named arguments example: for (final (countryCode, countryName) in countries) {
if (countryCode == 'BR') {
print('I live in $countryName');
}
} Named arguments example: for (final (key:, value:) in countries) {
if (key == 'CU') {
print('I live in $value');
}
} |
It's interesting that we sometimes consider I still think we should wait for pattern matching and records before we introduce a new language feature for a problem that could potentially be solved by just iterating over an iterable of pair-records. |
My current long-term goal: Wait for inline classes (#2626), make it possible for them to implement non-inline-class types of their representation type, then change inline class MapEntry<K, V> implements (K, V) {
final (K, V) _pair;
MapEntry(K key, V value) : _pair = (key, value);
K get key => _pair.$0;
V get value => _pair.$1;
} That should make for (var (k, v) in map.entries) { ... } If we get class modifiers before inline classes, I'll try to make Let's see how far we can get towards that. (Just being a subtype of |
for (var (k, v) in map.entries) { ... } is a big improvement, but the for (var (k, v) in map) { ... } |
The problem with allowing We'd have to decide which behavior to use based on the static type of the It's doable. It's even doable for Edited: I did mean |
when you said at any rate, if this syntax for (var (k, v) in map.entries) { ... } is available, i'm guessing it wouldn't be too hard to have the compiler implement logic like you hinted at possibly using a static type check to make the decision when the static type is not dynamic. |
Currently, if the static type does not implement Also, today, if a class can ever implement both |
Randal L. Schwartz suggests defining the following extension (which you can do in your own code or we could maybe add to the core libraries at some point): extension MapExtensions<K, V> on Map<K, V> {
Iterable<(K, V)> get keyValues => entries.map((entry) => (entry.key, entry.value));
} With that, you can now write: for (var (key, value) in map.keyValues) {
print('$key: $value');
}
var otherMap = {
for (var (key, value) in map.keyValues)
key + 1: value * 2
};
var list = [
for (var (key, value) in map.keyValues)
key + value
];
var set = {
for (var (key, value) in map.keyValues)
key + value
}; If we do #2563, then the extension isn't needed at all and you can just use: for (var (:key, :value) in map.entries) {
print('$key: $value');
}
var otherMap = {
for (var (:key, :value) in map.entries)
key + 1: value * 2
};
var list = [
for (var (:key, :value) in map.entries)
key + value
];
var set = {
for (var (:key, :value) in map.entries)
key + value
}; Given that, I think it's unlikely that it would be worth it to add special-case support for iterating over key-value pairs to for-in loops. Patterns and records already (with this use case in mind) work in for-in loops and allow you to bind multiple variables per iteration. I'm going to go ahead and close this, but it's a great suggestion to draw attention to an annoying wart in the language which should hopefully be much less annoying now. |
records are an improvement, but needing an extension is annoying. i don't want to have to remember the name of the extension and import it just to do one of the most basic things one ought to be able to do with a map. and since it's an extension, standard tools probably won't autocomplete the method name at least until you remember the name of the import for yourself. so as hinted at, adding this to the core libraries would improve convenience a lot. similarly, having to use any method name just to iterate over a map is annoying. as i mentioned before, i feel like this minor tragedy is because of the history of the development of the language. if records had been there from the beginning, one could have made |
Every programming language carries the sins of its past. There is no escaping path dependence. |
when
xs
is anIterable
, the syntaxfor (var x in xs)
is available inside both imperative code and list/set/map literals.it would be very useful to extend this syntax to maps.
examples:
the current workarounds hurt readability and/or efficiency:
The text was updated successfully, but these errors were encountered: