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
reflect: add Value.Clear #55002
Comments
cc @dsnet |
Interesting observation about NaN. It does mean that the documentation on // Clear removes all entries from m, leaving it empty.
func Clear[M ~map[K]V, K comparable, V any](m M) since it doesn't always leave it empty. \cc @ianlancetaylor |
FWIW that observation was made by @randall77 here, I'm not taking credit. |
Suddenly I like #20660. |
It's definitely a little odd to add something to reflect that you can't do in the language proper. Seems like we should fix that somehow first. |
This proposal has been added to the active column of the proposals project |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
@rsc For my purposes, I'd also be okay with having v.MapClear()
if v.Len() > 0 { // there where some NaNs in that map
v.Set(reflect.New(v.Type()).Elem())
} That way, |
There are never any good answers involving NaNs. |
Personally, I would like something like that. However, this does open the door to other functionality in For example, #54454 proposes |
An arbitrary suggestion: Then adding |
That's kind of just kicking the can down the road one step. I would argue that I'm ok with |
One possible halfway point would be to have |
A bit semantically strange, the existence of map.Clear that wouldn't actually clear the map. If there was such an operation, I would expect it to work on clearable maps, i.e. where map keys are proven to have reflexive comparison. Otheriwse that could easily leak into Set types for example, especially when computing cardinality. (sets of floats or floats composites). But then if it requires modifying map.Clear from an x package, how many programs it would break is another question too perhaps. [edit] to be fair, I'm not sure that the true semantics of map clearing have to rely on reflexive comparability. In that case, assistance from the runtime would be relevant. But then there is still a similar issue for user-defined datastructures. Leaving the NaNs and related in could also leak memory no? |
@bcmills to me, that feels like the kind of perfect compromise in that it leaves everyone unhappy. Especially as it doesn't seem possible to check if |
I find the nuance in this discussion quite interesting, but I thought I'd point out that I have never in eight years of writing Go used |
Me neither, but if the issue appears, it might appear for any type which is a composite of floats values. Not just directly float32 or float64. What happens if a pointer value is stored for a struct key where one field is a NaN float64 for instance? Isn't it now dangling? |
@Merovius, while it's true that one couldn't always check for the panic locally immediately before making the call to |
@bcmills I don't like that. As a library author using Not to mention that checking if an inserted value has this problem isn't always easy. @mvdan I tend to agree. I feel that right now, this issue - at least as far as NaN is concerned - is simply blocked on #20660 - i.e. "somehow decide what to do about NaN in map keys":
|
No, it can still be accessed using |
It is always easy:
That may be true, but if a caller puts an irreflexive key in a map they're almost certainly going to have trouble with way more than just your library. (How many other Go libraries assume that they can So I don't think users of your library would lose much, if at all, by having the additional “keys must be reflexive” restriction. |
Maybe "dangling" was a poor choice of a word. |
(3) would essentially be #45328 which was declined last year |
Not just essentially, exactly that mechanism with exactly that syntax was suggested. Interesting. Obviously, |
I think it's fine given that the NaN keys and wanting a reflect API are both factors which weren't properly considered in the previous proposal. @rsc in your option 3, would we end up with one or two new reflect APIs? My intuition is that "clear the map except NaN keys" is not worthwhile. |
If NaN containing keys are always a mistake, then perhaps that (2) is sufficient and the actual issue is to prevent these NaN containing keys in the first place. Option 3 could actually mask the mistake. If there are legitimate cases for these NaN containing keys, then (3) should be fine. I am more inclined toward option 2. |
That is pretty much exactly #20660, and I think it's also a good option. (But I may be biased because I filed it. |
Just to be clear, I have a strong preference against that particular variation on option (2). Instead, I would prefer: But I think option (3) is probably fine. |
#45328 was declined in part because we said the loop was just as good. But now we've realized that the loop does not handle everything, which is why we're back to a language change. |
Created #56351 for the language change. If that goes through, we'd add reflect.(*Value).MapClear to do the same thing (clear the map entirely, even NaNs). We wouldn't need maps.Clear(m) because delete(m) already does it. |
#56351 is accepted (soon), so we should revive this. Because clear(x) applies to slices and maps, we should call this Value.Clear and then it applies to slices or maps and otherwise panics. |
Based on the discussion above, this proposal seems like a likely accept. |
No change in consensus, so accepted. |
Change https://go.dev/cl/457895 mentions this issue: |
Ops, the issue is not done yet, need to wait for compiler implementation. |
Ah, this proposal is for reflect package, so should be closed after https://go.dev/cl/457895 merged. |
I propose adding a new method
MapClear
toreflect.Value
, which efficiently deletes all elements from a map.I am working on a decoder for a serialization format. If I want decoding into a non-nil map to leave it with only the serialized elements, I currently have two choices: 1. Allocate a new map, or 2. Clear all keys.
Clearing the keys has the advantage that it re-uses existing storage, if any, so it is lighter on allocations. But it takes more time to iterate over the map and clear keys. It also isn't correct, strictly speaking, as it doesn't behave right with NaN-keys.
It would be preferable to have a way to efficiently clear the map, preserving the already allocated buckets. This isn't an operation available in the Go language, so arguably it does not belong in
reflect
either. But we have #20138 to at least make the iteration-and-deletion idiom transparently efficient in plain Go.The text was updated successfully, but these errors were encountered: