Live data from Hacker News

No safe efficient ways to do three-way string comparisons in Go

go101.org

111–120 of 154 posts

Re: No safe efficient ways to do three-way string comparisons in Go

#111
post #14

People try to get cute with 3-way compares. A real Java bug that inspired: https://errorprone.info/bugpattern/BadComparable public MyFile implements Comparable { ... long timestamp; ... @Override public int compare(Object other) { return (int)(((MyFile)other).timestamp - timestamp; } ... } The int conversion loses the sign of the subtract. The particular use of the code was sorting files to delete the X number of old…

But of course the real solution is to use a strong and composable type for your comparison result, rather than remove the entire thing because you originally designed the API wrong.

Indeed. 1) Get strong types 2) Make a type representing Ordering 3) Use this type everywhere for ordering things. Stop worrying about it.

Using -1, 0 and 1 to represent these feels like something that was a clever trick for low level code on a PDP-11 and hasn't been a good idea since the 1970s.

Re: No safe efficient ways to do three-way string comparisons in Go

#112
post #41

The optimal version does seem to exist here (per the comment too): https://github.com/golang/go/blob/d28bf6c9a2ea9b992796738d03... So the goal was to intentionally nerf Compare() to discourage code the golang authors considered less clear. I'm not sure bad performance is really discouraging usage though, it just penalizes folks that use stdlib. I wonder if they'd accept a PR to switch to runtime.cmpstring today?

It actually used to call this, but was changed in 2015: https://github.com/golang/go/commit/fd4dc91a96518fdbb47781f9...

I'm not entire sure if I see the problem or follow why just using runtime·cmpstring is such a bad thing; doesn't seem that "overengineered" to me.

Re: No safe efficient ways to do three-way string comparisons in Go

#113
post #71

Earlier quoted context omitted.

“Avoid premature optimization” means to do the cleanest/clearest thing now, and only optimize later when you have the full picture. Arguably, that advice doesn’t apply to standard library functions anyway, at least not to the same extent. But if it did: How is adding a new, “bad” implementation any clearer than simply calling the already existing optimized one that the GP linked to?

You should optimize when it’s net useful, not just because you know how. Making a random function faster and harder to maintain is bad engineering if the speed isn’t useful.

Again: How is adding a new, “bad” implementation any easier to maintain than simply calling the already existing optimized one that the GP linked to?

Re: No safe efficient ways to do three-way string comparisons in Go

#114
post #14

People try to get cute with 3-way compares. A real Java bug that inspired: https://errorprone.info/bugpattern/BadComparable public MyFile implements Comparable { ... long timestamp; ... @Override public int compare(Object other) { return (int)(((MyFile)other).timestamp - timestamp; } ... } The int conversion loses the sign of the subtract. The particular use of the code was sorting files to delete the X number of old…

But of course the real solution is to use a strong and composable type for your comparison result, rather than remove the entire thing because you originally designed the API wrong.

I like how Rust does it with the `Ordering` type and associated combinators: https://doc.rust-lang.org/stable/std/cmp/enum.Ordering.html

For two values `x` and `y` of the same type with fields `a` and `b`, this lets you compare on `a` first and then on `b` by writing

``` x.a.cmp(&y.a).then(x.b.cmp(&y.b)) ```

Re: No safe efficient ways to do three-way string comparisons in Go

#115
post #95
post #41

The optimal version does seem to exist here (per the comment too): https://github.com/golang/go/blob/d28bf6c9a2ea9b992796738d03... So the goal was to intentionally nerf Compare() to discourage code the golang authors considered less clear. I'm not sure bad performance is really discouraging usage though, it just penalizes folks that use stdlib. I wonder if they'd accept a PR to switch to runtime.cmpstring today?

Completely OT but, after 5 years of writing Go, TIL you can assign multiple LHS from multiple RHS: c1, c2 := a[i], b[i]

Well, duh... I mean, that's the same mechanism that allows a function to return multiple values, and Go prides itself on its orthogonal features, so of course you can do that. Also handy for swapping: "x, y = y, x". Go isn't always more verbose than other languages...

Re: No safe efficient ways to do three-way string comparisons in Go

#116
post #102

Earlier quoted context omitted.

Go marks features as deprecated, though, both in source code and in the docs. For example, strings.Title() has been deprecated and instead the case package should be used. The backwards guarantee merely means that the feature won't be removed from the library in Go 1.x, but when you write new code you won't use it and the preferred way of doing the same is mentioned in the docs and version notes. I think it's good no…

Except Go certainly is never getting another major version, I am waiting for Go 1.10000.0, given how decisions are made on the ecosystem.

What's wrong with Go 2 with tools to automate migrations? Of course that limits the scale of possible changes, but moving methods between packages should be possible with this approach.

Re: No safe efficient ways to do three-way string comparisons in Go

#117
post #114

Earlier quoted context omitted.

But of course the real solution is to use a strong and composable type for your comparison result, rather than remove the entire thing because you originally designed the API wrong.

I like how Rust does it with the `Ordering` type and associated combinators: https://doc.rust-lang.org/stable/std/cmp/enum.Ordering.html For two values `x` and `y` of the same type with fields `a` and `b`, this lets you compare on `a` first and then on `b` by writing ``` x.a.cmp(&y.a).then(x.b.cmp(&y.b)) ```

In fairness that was directly inspired by Haskell’s type of the same name: https://hackage.haskell.org/package/base-4.17.0.0/docs/Prelu...

Re: No safe efficient ways to do three-way string comparisons in Go

#118
post #53
post #41

The optimal version does seem to exist here (per the comment too): https://github.com/golang/go/blob/d28bf6c9a2ea9b992796738d03... So the goal was to intentionally nerf Compare() to discourage code the golang authors considered less clear. I'm not sure bad performance is really discouraging usage though, it just penalizes folks that use stdlib. I wonder if they'd accept a PR to switch to runtime.cmpstring today?

> "intentionally nerf Compare() to discourage code the golang authors considered less clear" If that's true, it further proves that I disagree with the philosophy of the Go designers on pretty much everything. If your language provides multiple ways to do something, they should all be optimized in good faith. To do what you suggested is insane and user-hostile.

A sane language would deprecate the function so the compiler warns (or dies) when encountering it. Go's compiler is happy to die because I have an unused import, but not this?

Re: No safe efficient ways to do three-way string comparisons in Go

#119
post #53

Earlier quoted context omitted.

> "intentionally nerf Compare() to discourage code the golang authors considered less clear" If that's true, it further proves that I disagree with the philosophy of the Go designers on pretty much everything. If your language provides multiple ways to do something, they should all be optimized in good faith. To do what you suggested is insane and user-hostile.

Well, the question is what you want to optimize for. It's a library function that exists for consistency's sake; it's clear and simple, and reasonably fast (and near optimal in some cases). For optimal performance but suboptimal clarity, they could use a runtime implementation, but ideally the clear code would be fast, so best not to compromise the clarity for performance unless it proves important. I've been followi…

The most classic optimization advice is based on a complete misquote. Here is some critical context:

> t. The conventional wisdom shared by many of today's software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by pennywise-and-pound-foolish programmers

> in established engineering disciplines a 12 % improvement, easily obtained, is never considered marginal

> when it's a question of preparing quality programs, I don't want to restrict myself to tools that deny me such efficiencies.

> We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

Keep in mind that in this case the argument is being made against goto, which is effectively an inlined `jmp` instruction that can do all sorts of insane things just to save a few instructions. This quote is discouraging a case where the complexity is extreme and the benefit is minor.

All that people can seem to remember is "premature optimization is the root of all evil".

[PDF] https://dl.acm.org/doi/pdf/10.1145/356635.356640

Post reply on HN