-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
spec: add clear(x) builtin, to clear map, zero content of slice #56351
Comments
This proposal has been added to the active column of the proposals project |
Personally, I'm ok with it but can't determine if it is good enough. Having a way to disallow NaN containing values in maps would be best. Then map clearing via iteration just works and the change in this proposal is unnecessary (if not for perf reasons). Otherwise, comparing two maps may still have edge cases. (the crux of the issue is that comparison is actually underspecified it seems). With this proposal, map clearing gets solved but not inadvertent comparison of potential NaN composites. Other than that, this proposal should be semantically sound at least. |
I tend to agree that this is really only about NaNs, and is a peculiar response to their presence. At least, if you want to justify a new predefined function with a new capability, making NaNs the selling point is off-key (see what I did there?). |
I worry that this could lead to programmer error when clearing |
With
|
I think this proposal strictly improves the situation for irreflexive keys: if you use it it does the right thing for clearing the map, and if you don't use it you're no worse off than if it never existed. That said, this still wouldn't help use-cases that need to add and remove individual keys: The programming mistake I'm more worried about is typos. If both |
I would assume this does not release the memory, just as the delete-with-a-for-loop doesn't. If we ever implement #20135 the map will shrink eventually if it is never refilled. |
@carlmjohnson To be clear, what's the programming error? Both of these would work fine ISTM. For the first I can see that perhaps a programmer might've thought it deletes the inner maps (though that seems a bit far-fetched to me). But the second?
You are not.
What's the misuse? Semantics don't change. I am opposed to specify allocation behavior. That's an optimization that's up to implementers. |
What @bcmills said, a typo of |
I'm not too worried about this. For one, any reasonable test would catch this mistake. Second, you're not actually using |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
While I understand the motivation to reuse a predeclared function name here, I'm concerned because |
It wouldn't. All the builtin functions are predeclared identifiers. Adding new predeclared identifiers is backwards compatible - cf. That's not saying we should (I have no strong feelings), but this, at least, is not a reason not to do it. |
at the cost of having an overloaded built-in function that behaves differently based on the number of arguments. It's less user-friendly and more cognitively demanding to think about language features in terms of exceptions and/or gotchas, instead of just relying on different functions doing different things. Yes, the language already has overloaded built-ins e.g. Moreover, this would improve clarity if the new built-in went a step further and do additional things that |
If #20135 is implemented what would be the actual difference between delete(m) and m = nil // this is not actually needed
m = make(map[type1]type2) ? |
If this proposal is adopted as delete(m), and if #20135 is implemented without any new API, then it would depend on the heuristic(s) adopted in #20135, but I would guess delete(m) would clear the elements but leave the capacity. There is some related conversation in a different issue #54454, including this comment from Keith in #54454 (comment)
Perhaps #20135 and this proposal could be solved together ( |
The difference comes down to aliasing. What happens if other variables have a reference to the same map? See #56351 (comment) |
I really don't like that Personally, I think that it's a bug that you can have values that aren't equatable as map keys, and changing the language to better handle problems caused by that bug is not a good idea. I understand we can't change the fact that NaN is a valid map key, but we don't have to perpetuate the error by adding features to make it more usable. My first test for most languages features is "is this just trying to avoid writing a loop or if statement?" and if it is, I put it loooow on the list. If we ignore the NaN edge case, that's all this is. I'm not sure I've ever cleared a map in production code (though I do understand the uses). I am pretty sure I've never used floats as keys in a map. Adding a language feature for a tiny edge case based on a bug seems like an easy "no". That being said, if people reeeealllly want this, maybe make it |
FWIW one of the reasons this is being asked for now is that I wished to have a method in So, for me, this isn't really about the syntactical overhead and effort of writing a loop. It's about being able to clear a map from reflect at all, without having to pay the allocation to iterate it first and then pay the allocations for all of its storage when growing it again. I agree that it would be better if we could've done something about irreflexive keys before Go 1. But to me, the reason for this isn't really to be able to clear them out. That's such an edge-case, it doesn't even factor into the calculation for me. As I said here, I'd even want something like this if |
I want to note that the proposed That analogy suggests that perhaps we should permit |
I'd vastly prefer |
I think I can understand why people would like to dissociate map clearing and delete. In one case, everything is deleted regardless of the key. In the other, NaN containing keys would not be deleted. Is this an issue? |
Fixes golang#56351 Change-Id: Ia87bf594553b7d0464b591106840f849571c5f39 Reviewed-on: https://go-review.googlesource.com/c/go/+/467755 Auto-Submit: Cuong Manh Le <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Run-TryBot: Cuong Manh Le <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> TryBot-Bypass: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
Change https://go.dev/cl/481935 mentions this issue: |
So iterators that are in progress can know entries have been deleted and terminate the iterator properly. Update #55002 Update #56351 Fixes #59411 Change-Id: I924f16a00fe4ed6564f730a677348a6011d3fb67 Reviewed-on: https://go-review.googlesource.com/c/go/+/481935 Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Cuong Manh Le <[email protected]> Run-TryBot: Cuong Manh Le <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Keith Randall <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
Change https://go.dev/cl/498755 mentions this issue: |
Also move all the language changes to the same part of the release notes. For #56351 For #57411 Change-Id: Id1c51b5eb8f7d85e61a2ae44ee7d73bb13036631 Reviewed-on: https://go-review.googlesource.com/c/go/+/498755 TryBot-Bypass: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
I dont see this mentioned yet, so let me do so now:
https://tip.golang.org/ref/spec#Clear this does not make sense, at least to me. |
@4cq2 "Argument type" in this context means "the type of the argument" not "the type given as argument" (that is called a "type argument" in the spec. Isn't language fun?). I guess that could be made explicit, to remove that ambiguity? |
Yeah, happy to use a more lucky formulation that is not too clunky. But the meaning here is, in italics: If the argument type (the type of the argument provided to clear) is a type parameter (is of type parameter type), all types in its type set (in the type set of the constraint corresponding to the type parameter) must be maps or slices, and clear performs the operation corresponding to the actual type argument (corresponding to the type of the actual type argument with which the type parameter was instantiated). |
@griesemer I think I would definitely replace "argument type" with "type of the argument" or introduce a name for it (" |
Reopening so we can reconsider spec wording. |
it takes very little code to demonstrate the case and that could be used to introduce a good name to refer to: func genericUseOfClear[T TypeSet](v T) {
clear(v)
} |
Change https://go.dev/cl/510935 mentions this issue: |
Per feedback on #56351. For #56351. Change-Id: I63dd1713a1efe4d7180d932dbd8e1510cbb32e90 Reviewed-on: https://go-review.googlesource.com/c/go/+/510935 TryBot-Bypass: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
Spec prose was adjusted. Closing. |
There is no way to clear a map in Go. You can write
but that only works if m does not contain any key values that contain NaNs.
Based on the discussion in #55002, we suggest adding
delete(m)
to the language to clear the map, always (even if it contains NaNs).This is somewhat a reopening of #45328, which we closed because the loop was good enough, but we missed the earlier discussion in that issue of NaNs.
Adding delete(m) would then let us also add a similar mechanism in reflect.
We wouldn't need to add maps.Clear(m) since delete(m) is just as good.
The text was updated successfully, but these errors were encountered: