-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
maps: add iterator-related functions #61900
Comments
This proposal has been added to the active column of the proposals project |
Finishing this proposal discussion is blocked on #61405. |
Change https://go.dev/cl/558736 mentions this issue: |
It is unfortunate that |
@earthboundkid ISTM if that is a concern, it should maybe rather be I get, FWIW, that "get the sorted keys from a map" is a fairly common use case, to try and get deterministic order from the specifically non-deterministic maps. But it still seems a more general problem. |
maps.Keys could return a sequence implementation with a length hint and slices.Sorted could type assert for that, similar to what some io.Reader functions do. |
Nevermind, iter.Seq is a concrete type, not an interface. |
It's true that slices.Sorted(maps.Keys(m)) will not pre-size the slice, but that's not necessarily a strike against the iterator forms. We could have a separate discussion about maps.KeysSorted and maps.KeysSortedFunc as optimizations, if that became a concern. |
Have all remaining concerns about this proposal been addressed? The full godoc is:
|
SortedKeys can wait and be a separate proposal. |
More wordy, but |
Based on the discussion above, this proposal seems like a likely accept. The full godoc is:
|
What, if anything, is guaranteed about the iteration order of Keys and Values (EDIT: and All)? I believe this should be specified in the docs. Does these two for loops yield the same key order? I would assume not, based on analogy to range-over-map.
What about this?
I can see why it might make sense from an implementation standpoint for this to also be randomized. However it also seems weird for a value of type Seq, which nominally represents a sequence, to in fact yield multiple different sequences. |
|
@earthboundkid An iter.Seq is not an iterator and does not exhaust. |
Yes, I deleted my comment but you beat me to it. 😄 |
Happy to update docs to say that iteration order is undefined (different each time) and Insert does overwrite keys. |
No change in consensus, so accepted. 🎉 The full godoc is:
|
@rsc I don't see any doc changes |
Change https://go.dev/cl/586716 mentions this issue: |
@Merovius there are other cases when you need to collect the iterator, like when that can only be safely done under a lock and you wouldn't want to hold onto the lock while rangeing over it. That sounds more like a general pre-allocating keys/values to slice function is desirable than a specific |
I added an issue for slices.CollectN #68261. |
I'm coming to this quite late, but I have a question: Why do functions AFAIU, all those functions could have been written as follows without losing any expressive power: func All[K comparable, V any](m map[K]V) iter.Seq2[K, V]
func Insert[K comparable, V any](m map[K]V, seq iter.Seq2[K, V])
func Keys[K comparable, V any](m map[K]V) iter.Seq[K]
func Keys[K comparable, V any](m map[K]V) iter.Seq[V] |
Because custom map types, i.e. |
@DeedleFake No; as long as the argument is of some type whose underlying type is some map, no explicit conversion is required from the caller. package main
import (
"iter"
)
type Example map[string]string
func main() {
m := Example{"key": "value"}
_ = Keys(m) // no compilation error
}
func Keys[K comparable, V any](m map[K]V) iter.Seq[K] {
return func(yield func(K) bool) {
for k := range m {
if !yield(k) {
return
}
}
}
} |
@jub0bs I think the answer is "because of consistency". It does make a difference for functions like maps.Equal, because a usage like Of course now people are justifiably confused about when to add them and do it inappropriately, because they cargo-cult from the In general, if it is foreseeable that a function might be used with a higher-order function, it makes sense to add the extra type-parameter. And to be fair, I can imagine that functions like |
@jub0bs For consistency with the other functions in the maps package, so that an explicit instantiation always starts with the map type. |
We propose to add the following functions to package maps, to provide good support for code using iterators.
This is one of a collection of proposals updating the standard library for the new 'range over function' feature (#61405). It would only be accepted if that proposal is accepted. See #61897 for a list of related proposals.
All serves as a “source” for iterators.
Keys and Values are like All: not terribly useful by themselves but useful as inputs to other iteration adapters.
In particular, we expect that
x := slices.Sorted(maps.Keys(m))
will be a common pattern.Insert and Collect serve as “sinks” for iterators.
The text was updated successfully, but these errors were encountered: