3 ms·
This is really interesting. I never use three way string comparison, and so I wondered when other programmers use it. (The obvious use case is sorting, but in
by jrockway 4y ago
This is really interesting. I never use three way string comparison, and so I wondered when other programmers use it. (The obvious use case is sorting, but in Go, sort.Interface expects a Less function and sort.Slice accepts a "Less" function, so you won't use it there.)
I searched through my random checked out applications to see who calls strings.Compare, and why.
Most of them are mistaken sorting. In gVisor, there is this in a test:
...
cmpopts.SortSlices(func(a, b testEntryEventInfo) bool {
return strings.Compare(string(a.Addr), string(b.Addr)) < 0
}),
...
This pattern shows up a bunch:
// Less implements sort.Interface.
func (s fooSlice) Less(i, j int) bool {
return strings.Compare(s[i].Whatever, s[j].Whatever) == -1
}
In Go's Snowflake library, there is this:
if strings.Compare(s0, name) != 0 {
t.Error("a file was not downloaded by GET")
}
This is exceedingly interesting to me because you'd expect Compare to cost more than < (it does more stuff), and yet people are somehow baited into writing it. I'm guessing what happens is that people don't know that "<" works for strings, and they reach for strings.Compare, so the documentation is trying to talk them out of a program that doesn't actually make sense. In the case of "!= 0", they just wanted "s0 != name", which I take to mean they had absolutely no idea that strings in Go are comparable at all.
All in all, I get the impression that people coming from other languages to Go have different expectations about what the language can do. The documentation for strings.Compare is a logical place to correct them, but it doesn't bother. Just a comment that says "sucks if you use this".
BTW, there were a couple of correct uses. Gazelle has a sort function like this in a few places:
sort.SliceStable(sortedFiles, func(i, j int) bool {
if cmp := strings.Compare(sortedFiles[i].Path, sortedFiles[j].Path); cmp != 0 {
return cmp < 0
}
return sortedFiles[i].DefName < sortedFiles[j].DefName
})
Here they are punished for the inefficiency of strings.Compare; they would actually take advantage of it in the common case where the paths aren't equal over the easier approach of:
if xs[i].Path != x[j].Path {
return xs[i].Path < xs[j].Path
}
return xs[i].DefName < xs[j].DefName
Another correct use was in "goja" (a Javascript interpreter), which uses strings.Compare to implement Javascript's <string>.compareTo(<string>). Whether or not Javascript code is using compareTo correctly is an analysis I do not have the energy to do :)
- Dylan16807 4y ago> This is exceedingly interesting to me because you'd expect Compare to cost more than < (it does more stuff), and yet people are somehow baited into writing it. I would expect it to be the same within a couple nanoseconds, because "more stuff" is an extremely small amount of stuff. The naive direct implementation of a 3 way compare does the exact same comparisons as a direct implementation of less than, it merely returns more information, which makes it more generally useful.
- jrockway 4y agoYeah. To me, I just think it's weird to ask for two pieces of information and then throw one of them away. Sometimes it's not a performance hit, but I feel like it's one of those things where you should get a feeling "I might be doing this wrong". But if you don't know that < exists (and obviously searched for strings.Less), then you won't get that feeling. That's what I find so fascinating; if other people's feelings are similar to mine, then they simply didn't know that you were allowed to use < here.
- Dylan16807 4y agoI don't see it as two pieces of information. It's returning one idea either way, but the tri-state tells you more than a boolean.
- coding123 4y agoBut that is more useful, we should agree, for implementing binary trees or sorting algorithms.
- quelltext 4y ago> so the documentation is trying to talk them out of... What documentation though? There's an internal comment but it's not documentation and it's not really arguing against the use of this type of comparison (just against use of the implemented function). If the documentation for this function went on along the lines of "we discourage the use of 3 way compares as we consider it an antipattern, do X instead, there's literally no reason to ever use 3 way compares, we know it, here's why..." maybe, but it doesn't. Now, maybe 3 way comparison is not common but it is a distinct operation with known optimization opportunities. I wouldn't readily claim that the operation is not needed by anyone.