-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
net/netip: add Prefix.Compare and AddrPort.Compare #61642
Comments
Can we get by with just Compare now? |
Probably, yes. Less is still reasonably common when wielding the stdlib in 1.20 due to |
This proposal has been added to the active column of the proposals project |
Retitled to be just about Compare but to also add AddrPort. |
Based on the discussion above, this proposal seems like a likely accept. |
I'm not aware of any remaining concerns. Doing just Compare LGTM, that's the only feedback so far apart from thumbs-ups. |
I miss a discussion that the suggested ordering is a commonly used one. Is there any popular software that sorts it that way? Would be sad, if we later discovered that Go does it differently and a lot of Go software needs to implement it themselves differently to be compatible. (maybe even after getting bug reports about that) |
@nightlyone, @danderson wrote above:
|
No change in consensus, so accepted. 🎉 |
Fixes golang#61642 Signed-off-by: David Anderson <danderson@tailscale.com>
Change https://go.dev/cl/524616 mentions this issue: |
I know I'm way too late to join the discussion, but I just saw the topic in the 1.22 RelNotes. I've never seen a routing table in that order: and this would be the sort order of this proposal |
We should not compare apples with oranges. The Python library With the python library Please see the introductory text https://docs.python.org/3/howto/ipaddress.html#ipaddress-howto and the chapter Defining networks Completely independent of python (but python does it right with the right library in the right context), the suggested sort order does not reflect the output of |
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ipaddress import *
>>> p1 = ip_network("0.0.0.0/32")
>>> p2 = ip_network("10.0.0.0/8")
>>> p1 < p2
True same result as with the |
@danderson @rsc take the first column as input for the https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml and then take my proposed sort order algo und compare the tests:
|
It sounds like we should unexport Prefix.Compare but we can leave AddrPort.Compare. I will send a CL. |
@rsc @danderson one more remark, this time to // Compare returns an integer comparing two AddrPorts.
// The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2.
// AddrPorts sort first by IP address, then port.
func (p AddrPort) Compare(p2 AddrPort) int {
if c := p.Addr().Compare(p2.Addr()); c != 0 {
return c
}
return cmp.Compare(p.Port(), p2.Port())
} why using inside the package the public methods? Why not just using the private struct members? // AddrPort is an IP and a port number.
type AddrPort struct {
ip Addr
port uint16
} func (p AddrPort) Compare(p2 AddrPort) int {
if c := p.ip.Compare(p2.ip); c != 0 {
return c
}
return cmp.Compare(p.port, p2.port)
} for me it sounds we should stop this as a whole for this cycle and do it again in the next release. Maybe Dave coded this in hurry. Maybe a copy-paste error, since Dave used parts of this code snippet already in his own codebase, outside of |
@gaissmai, are you saying there is something buggy about the AddrPort implementation? I don't see anything buggy. It sounds like you are reading something into the fact that the code uses p.Addr() instead of p.ip and p.Port() instead of p.port. There is absolutely nothing wrong with using exported methods inside a package. In this case they will inline to the basic field accesses. |
Change https://go.dev/cl/549615 mentions this issue: |
@rsc no there is nothing buggy, but it smells in comparison to other methods in the func (p AddrPort) IsValid() bool { return p.ip.IsValid() } and not func (p AddrPort) IsValid() bool { return p.Addr().IsValid() } it's just inconsistent and the method calls introduces unnecessary line noise and cognitive load on the reviewer due to another unnecessary indirection. |
I'm one of the original authors of this package (also, it's Dave not Dan). It's funny being accused of not having the same style as myself :). How the internals of the package access stuff really doesn't matter. Looking back at the package history, the access using internal fields is likely a holdover from a previous API of the package, where the fields of AddrPort were exported directly rather than using an accessor method. Whoever did the mechanical change to create the accessors kept the field accesses intact, presumably because it was the easiest search-and-replace to execute. It doesn't represent any complex philosophical choice about code layout, it represents an unimportant piece of the package's historical structure. If anything, the argument about cognitive load goes in the opposite direction where performance is identical: everyone has to learn the exported API to use the package anyway, so reusing that API internally allows the reader to reuse their existing knowledge of the behavior. The change to the prefix ordering seems fine to me. As I said originally, what I care most about is that some ordering exists and doesn't force everyone to reimplement their own (and miss edge cases like the zero address). We can make that change for the next release. |
API questions remain, so we decided to back it out for Go 1.22. Code still lives in the repo, just unexported. For golang#61642. Change-Id: Iccd91b0da48ae72dec9f660476826a220c7ca4be
danderson@4a6a7b8 implements the revised ordering, with some additional test cases to lock the order in and verify that the sort matches IANA's ordering. @rsc I made this commit stack on top of your unexport CL, on the assumption that I'll send it out once the tree opens for 1.23. If you'd rather sneak the corrected ordering into 1.22, happy to unstack the change and send a CL post-haste, your call. |
@danderson thanks! |
You're correct. Removed the explicit bitlen test and added a comment to point out the implicit valid+family ordering. The tests prevent a regression there anyway, but it seems useful to document for a future reader who wonders why the API docs list 5 ordering criteria but only the last 3 explicitly happen. |
@danderson LGTM and thanks for |
API questions remain, so we decided to back it out for Go 1.22. Code still lives in the repo, just unexported. For #61642. Change-Id: Iccd91b0da48ae72dec9f660476826a220c7ca4be Reviewed-on: https://go-review.googlesource.com/c/go/+/549615 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Anderson <dave@natulte.net> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Damien Neil <dneil@google.com>
As |
API questions remain, so we decided to back it out for Go 1.22. Code still lives in the repo, just unexported. For golang#61642. Change-Id: Iccd91b0da48ae72dec9f660476826a220c7ca4be Reviewed-on: https://go-review.googlesource.com/c/go/+/549615 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Anderson <dave@natulte.net> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Damien Neil <dneil@google.com>
@danderson May I ask what the status is for Prefix.Compare? What else needs to be done for it to be included in 1.23? |
In our code, we've ended up writing ad-hoc ordering functions for netip.Prefix a whole bunch of times, for use with sort.Slice and the new slices.SortFunc. Writing those ordering functions is repetitive, and just tricky enough that it's easy to write comparators that don't conform to the contracts that sort and slices specify.
I propose adding
Prefix.Less
andPrefix.Compare
to net/netip, so that people don't have to write their own ordering functions for prefixes.Less
is a trivial wrapper aroundCompare
.Compare
orders two prefixes as follows:An example ordering:
Back when we first wrote net/netip, we hesitated to add
Less
andCompare
to prefix, because there didn't seem to be an obvious order we could impose: Prefixes organize themselves naturally into a binary tree rather than a flat list. So,Contains
has an obvious definition, as doesOverlaps
, butLess
andCompare
would require us to come up with some arbitrary flattening of the tree to make sense.Now that we have a bit more experience with using net/netip in the wild, I have two arguments for implementing
Less
andCompare
as defined above:ip route show
, and virtually all other network-oriented software. That order is the one specified above, where smaller prefixes appear first, and so the list reads from most general to most specific. This is also the order you get when implementing a binary tree as an array, or when you place prefixes into a tree and traverse it breadth-first.While we're in there, AddrPort also lacks comparators, so we could add those as well. The above discussion doesn't apply to AddrPort, in that there is an obvious ordering available (order by Addr first, then Port). Looking back, I believe we simply forgot to make AddrPort's API consistent with Addr.
The text was updated successfully, but these errors were encountered: