-
Notifications
You must be signed in to change notification settings - Fork 18k
sort: clarify Slice comparator requirements #73420
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
Comments
Related Issues Related Code Changes (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
Change https://go.dev/cl/666355 mentions this issue: |
I'm not certain that changing the spec is the way forward here. I'd rather change the implementation so that it conforms to the spec as written. |
@randall77 think of this as a clarification and not a change to the doc. the doc is written poorly. practically speaking, everyone assumed strict weak ordering. but it was written in a way that, I'd argue, gave weaker requirements than is necessary. I've changed the title |
Should we just require a strict weak ordering everywhere then? |
Yes, I've changed it. we already require a strict weak ordering everywhere, this just clarifies that. As for the difference in sort vs stable, I've dropped that. There is a different in the requirements only from the implementation, but not the doc. I'd prefer it to be part of the doc / spec as well, but that would require more work in justifying. And, I see that C++ stdlib doesn't provide a public distinction either, so it's probably best to just stay consistent anyway. |
Do you have an example of a sort that actually goes wrong with a non-strict-weak-ordering comparison? Particularly, an ordering which is transitive and asymmetric but is (sometimes at least) reflexive. |
Sure, here's an example which satisfies the letter but not the spirit of the current spec:
To clarify why this works, let's look at the current spec:
This says nothing. We are defining what less means! So it's circular.
This part doesn't matter, since like above, we are defining what "equal" means through the comparator so this part also says nothing. But anyways: requirement is never used since
Not applicable.
This will always be satisfied since
Will never occur since |
I don't agree. This says a lot. To me it means that Less(i, j) implies that s[i] must appear before s[j] in the output. It is not possible to satisfy that if i!=j and both Less(i, j) and Less(j, i) are true. And this presumably also implies that we can't have Less(i, i) be true, because then s[i] must appear before itself. Depending on whether you agree that "before" here means "strictly before", which I think is clear but maybe there's a bit more wiggle room than the previous paragraph. |
That you for your patience @randall77
Ok fair enough! So, if this statement:
Describes everything that is needed. From that alone, we can derive all three strict weak ordering properties. But then why is the transitive ordering line stated below that? It's confusing as it's like an elaboration on the specifics but only stating one. There is a standard way of stating these requirements and only this one part of the stdlib isn't using it. If the documentation for Less is defining a strict weak ordering, then it should say so using those words for clarity! I've got someone at my work who defined a complex comparator but didn't know these properties, and improving the doc is helpful for others. |
I don't think you can derive transitivity from that. Consider the case where only Less(1,2) and Less(2,3) return true. It is easy to satisfy "Less(i,j) => s[i] appears before s[j]", but that isn't a transitive relation. Particularly, Less(1,3) is false. In other words, !Less(1,3) does not imply that s[3] appears after s[1]. |
I agree that we should probably make all the docs consistent, if in fact all our implementations require the same thing. |
The doc for
sort.Slice
states:This is referring to the less function interface here:
This describes only transitive ordering. In contrast, the underlying algorithm, pdqsort, requires strict weak ordering.
This is an important distinction. If a comparator is, for example:
Then it will be conforming to the documented requirements yet will still cause crashes under nebulous implementation defined circumstances. e.g. the number of elements to sort is greater than 33, and elements happen to be in a specific order.
To fix:
Change the documented requirement of
sort.Slice
to what is stated insort.SortFunc
.The text was updated successfully, but these errors were encountered: