Most active commenters
  • hambes(4)

←back to thread

Hyrum's Law in Golang

(abenezer.org)
98 points thunderbong | 17 comments | | HN request time: 0.001s | source | bottom
1. hambes ◴[] No.42202204[source]
Solution to the specifically mentioned problem: Don't use string-based errors, use sentinel errors [1].

More generally: Don't produce code where consumers of your API are the least bit inclined to rely on non-technical strings. Instead use first-level language constructs like predefined error values, types or even constants that contain the non-technical string so that API consumers can compare the return value againnst the constant instead of hard-coding the contained string themselves.

Hyrum's Law is definitely a thing, but its effects can be mitigated.

[1]: https://thomas-guettler.de/go/wrapping-and-sentinel-errors

replies(6): >>42202257 #>>42202260 #>>42202261 #>>42202464 #>>42202551 #>>42202608 #
2. Svip ◴[] No.42202257[source]
In your example, the onus is on the consumer not the provider. I could still be writing code that checks if `err.String() == "no more tea available."`. I agree, I shouldn't do that, but nothing is preventing me from doing that. Additionally, errors.Is is a relatively recent addition to Go, so by the time people would check for errors like this, it was just easier to check the literal string. But as an API provider in Go, you cannot prevent your consumers from checking the return values of .String().
replies(1): >>42202284 #
3. gwd ◴[] No.42202260[source]
The frustrating thing is that the error in question already is a sentinel error -- Grafana (the top-level culprit in the linked search) should be using `errors.As(&http.MaxBytesError{})` rather than doing a string compare.

The whole point of Hyrum's Law is that it doesn't matter how well you design your API: no matter what, people will depend on its behavior rather than its contract.

replies(2): >>42202472 #>>42202475 #
4. adontz ◴[] No.42202261[source]
Honestly, this is so much worse than "catch". It's what a "catch" would look like in "C".
replies(1): >>42202287 #
5. hambes ◴[] No.42202284[source]
Unfortunately true. The Go maintainers might not agree with me on this, but I think in this case consumers have to learn the hard way. Go tries to always be backwards compatible, but I don't think that trying to be backwards compatible with incorrect usage is ever the right choice.
replies(1): >>42202783 #
6. hambes ◴[] No.42202287[source]
It might look worse than catch, but it's much more predictable and less goto-y.
replies(1): >>42202393 #
7. guappa ◴[] No.42202393{3}[source]
goto was only bad when used to save code and jump indiscriminately. To handle errors is no problem at all.
replies(1): >>42202435 #
8. froh ◴[] No.42202435{4}[source]
yes, yes, yes! see the Linux Kernel for plenty of such good and readable uses of go-to, considered useful: "on error, jump there in the cleanup sequence ..."
9. ◴[] No.42202464[source]
10. sssddfffdssasdf ◴[] No.42202472[source]
But it looks like that until 3 years ago, this string comparison was the only way to do it. https://github.com/golang/go/pull/49359/files
replies(1): >>42202498 #
11. LudwigNagasena ◴[] No.42202475[source]
Early Go lacked lots of features such as errors.As. It was and still is sometimes idiomatic to generate Go because it is so featureless and writing it is often a chore. So it is very much about how well you design your API.
12. gwd ◴[] No.42202498{3}[source]
Good catch. So in a sense this isn't really Hyrum's Law (which would be more appropriate to things like the Sim City / Windows 3.x UAF bug described in a sibling comment); it's more like, if people need to do something, and you don't give people an explicit way to do it, they'll find an implicit way, and then you're stuck supporting whatever that happened to be.
13. cedws ◴[] No.42202551[source]
Code that checks raw error strings is just plain bad and should be exempt from Go’s backwards compatibility guarantees. There is almost never an excuse for it, especially in stdlib.
14. karel-3d ◴[] No.42202608[source]
Using string error comparisons was the only way to do this few years ago; and Go has a backwards compatibility promise.
replies(1): >>42202634 #
15. ◴[] No.42202634[source]
16. LudwigNagasena ◴[] No.42202783{3}[source]
So the people who decided to make a stringly type error with `errors.New("http: request body too large")` and make you suffer, now can remove a stringly typed error and make you suffer even more? What would the lesson be? What would consumers learn?
replies(1): >>42203648 #
17. hambes ◴[] No.42203648{4}[source]
I don't understand your point. The lesson is "don't rely on magic strings, instead rely on exported and documented constants, otherwise your code might break".