-
Notifications
You must be signed in to change notification settings - Fork 87
Add .toMap extensions for tuples/pairs and key+value records #359
Add .toMap extensions for tuples/pairs and key+value records #359
Conversation
You'd need to add a changelog entry and a test here, please. Thoughts @devoncarew ? @natebosch ? |
We've discussed making I'm a little skeptical of shipping utilities that bridge records and map entries before then. Can you talk a little about your intended use case? Where are you getting an Iterable of records that is sensible to turn into a map? |
My main problem with I've considered changing Records are not simpler than classes. They're a little diffent. That can be both good and bad. |
@@ -914,6 +914,18 @@ extension IterableIterableExtension<T> on Iterable<Iterable<T>> { | |||
}; | |||
} | |||
|
|||
/// Extensions that apply to iterables of tuples/pairs (records with two unnamed elements). | |||
extension IterableTupleExtension<T1, T2> on Iterable<(T1, T2)> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not keen on just using a positional pair as the representation of a key/value pair.
I'd use a type like ({T1 key, T2 value})
instead. I can see that there is a version below that does that, so I would just drop this one.
It does get a little more verbose if you don't want to use key
and value
as the names for the key and value.
And if you do have a list of pairs, then having to do .map((p) => (key: p.$1, value: p.$2))
does feel unnecessary.
(Maps are not sets of pairs. Now that we have records, Set<(...,...)>
s are sets of pairs!)
/// Extensions that apply to iterables of tuples/pairs (records with two unnamed elements). | ||
extension IterableTupleExtension<T1, T2> on Iterable<(T1, T2)> { | ||
/// Returns a map from the first element of each tuple to the second element. | ||
Map<T1, T2> get toMap => {for (final element in this) element.$1: element.$2}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Just as style comments, not endorsing the functionality:
toX
functionality like toMap()
is usually a method, not a getter.
The for
loop can destructure: {for (var (key, value) in this) key: value}
.
This package doesn't use final
for local variables.
I'd use "Creates" instead of "Returns" in the comment. Never start a DocComment with "Returns".)
I feel like I have to do this all the time when transforming data, which is a lot of what we do as software developers. One prominent example that has come up a lot for me recently is when converting GraphQL data (which doesn't have a Map-type, so instead relies on lists of objects) into a more idiomatic Dart representation.
I approach this from a pure developer experience/ergonomics point of view. I would argue that from that perspective, something like:
is indeed simpler to write and parse than:
It would of course be even nicer if we had the shorthands available in Scala (
This is your taste, which is totally fine. Why does that have to mean you are against providing convenience for others that may prefer something else?
Indeed. I'm not sure I understand this comment though. There are a lot of things that can be reasonable to create maps from, depending on your use case 🙂 |
When creating a map, there is also the option that I'd recommend instead: {for (var e in myList) e.x: e.y} The need to work with If we had a shorter object destructuring, I don't think I'd need more. Going back and forth between |
Unfortunately this approach is not very conducive to fluent/functional style code.
Could you elaborate on this? Why is it better? I would be fine with using literal one-entry maps too, if there was an easy way to turn a list of maps into a single map in a fluent/functional style. E.g.:
In this case, I think having lambda shorthands would be even more handy. Then a general |
IMO, it's usually more readable. All the code is right there, the entry elements show the actual key and value directly. That is compared to constructors, which are not conductive to fluent style either. A If the example using myList.map(toEntries).toMap().somethingMore(); I can see why
Writing fluent code is not a goal. It's a means to expressing data flow. When the data structure starts mattering, like creating a map, it's no longer just data flow. Or said differently: If the result is not an iterable, it's a good place to break the selector chain. (But that's just, like, my opinion.) |
Makes sense.
I usually find this style to be a lot more readable, so I think it has a lot to do with familiarity and/or taste.
I agree that it is not a goal. I just tend to think it usually makes for more readable code. I didn't come here to argue about the virtues of writing fluent-style code. It is however a common style in the wild. Since I'm honestly sad to see that such an unobtrusive and simple contribution just be shot down based on opinions about style that you assume to be universal. The built-in capabilities for collection processing in Dart (even with |
I definitely do not assume my opinions on style are universal. I do try to keep a consistent and conservative style for the platform libraries and associated packages, which often means not adding something even though a lot of people may like it. There are many many APIs that a large group of people would like, there is just not a consensus on precisely which APIs, and adding all of them is a non-starter. So, conservative, and trying to not add something that we'd end up regretting in the future. I'd be willing to consider |
Another option without the intermediate Map.fromIterable(myList, key: (e) => e.x, value: (e) => e.y); |
Closing as the dart-lang/collection repository is merged into the dart-lang/core monorepo. Please re-open this PR there! |
Since records were introduced in Dart, they have become a much simpler way of representing a list of keys and values than
MapEntry
s.This change adds an easy way for users to turn them into maps.