5 ms·
Don't Panic
- alpb 6y agoIt would be great if mods edit the title. There's no mention of "Wouldnt wish this on my enemies" in the post, yet @bheni has added this to the title while posting to HN. Aside from that, I think that's just your opinion. Many people and large-scale projects have been happy with Go error handling. I personally like errgroup package and it solves a complicated problem cleanly. Be careful for what you wish for your enemy. ;)
- hombre_fatal 6y agoThough note that it's his own post. Could argue that it's not editorialization since he's appending to his original thoughts, not introducing a third-party opinion or interpretation of them. :P
- bheni 6y agoThis was referring to the pain I went through changing the code mentioned in this passage: As soon as I realized that Noms could panic when calculating the hash of its types I knew I was way off. In the end I think I spent closer to 6 weeks on this. It was time-consuming, and boring, but it couldn't be automated and every one of the changes was an opportunity to introduce bugs. You are right though, I didn't spend too much of the post talking about how much I hated that 6 weeks and how I regretted my life choices.
- deleted 6y ago[deleted]
- johncena33 6y ago> It would be great if mods edit the title. There's no mention of "Wouldnt wish this on my enemies" in the post, yet @bheni has added this to the title while posting to HN. Sensationalization has started slowly creeping into HN unfortunately.
- marcrosoft 6y agoThe author could have avoided all this pain by reading effective go and avoided panics like they recommend.
- ebiester 6y agoThe author was working with a codebase they didn’t write to start with, as stated in the article.
- gonzo41 6y agoRookie mistake, Always insist on a rewrite. :p
- sigzero 6y agoOr maybe you could have read the article and realized the author inherited a codebase and wasn't the Creator of it.
- cambalache 6y agoBut then the problem was not the language but the people who worked with it. This could happen with every language, even the venerable holy grails.
- DangitBobby 6y agoOnly if you ignore that it is the language design that encouraged the choices in the offending codebase that the author laments having to change.
- foolfoolz 6y agothis is the same argument for throwing exceptions vs returning Either. or similarly Future vs EitherT. handling all the cases sucks but it does make it really clear what choices your code is making
- SomaticPirate 6y agoWere these fixes contributed back to Noms?
- Someone1234 6y agoThey said it was a hard fork. I don't understand how they would submit such a large re-write and re-design back, it completely re-thinks how Noms works at a low level.
- aboodman 6y agoIt doesn't. We would have been interested in working with the Dolt folks. I would have probably helped convert the panics myself. They wanted to do their own thing. That's allowed in open source and part of the beauty. It does kind of make me sad though.
- dietrichepp 6y agoI recently took someone else’s tool and migrated the panics to errors. How painful it is depends on the size and complexity of the codebase. Fortunately, this was a relatively small codebase written by—what looked to me—like someone who knew how to program but was unfamiliar with Go conventions. So I spent a couple hours getting rid of panics, and afterwards I was able to use the tools.
- erik_seaberg 6y agoThe ergonomics of explicit error handling without monads and without pattern matching are so bad that the language designers gave up and allowed every pointer deref, bounds check, equality check, and send to panic. I may never understand why “if err != nil” is tolerated by engineers.
- dilap 6y agodoesnt every mainstream language panic (or undef behavior) on out of bounds array access? explicit error returns is a little clumsy, but still nicer than exceptions. (zig error handling seems basically perfect to me.)
- spullara 6y agoMany threaded languages throw an exception that can be caught and if not caught, kills that thread. Not the whole program. See Java, C#, etc.
- Thaxll 6y agoIf not cought you end up in a really bad state.
- recursive 6y agoIf you don't catch it, you generally don't end up in a bad state. More like a lack of a state altogether.
- apta 6y agoAny well-written framework will have a base-level exception handler. If not, it will simply exit the program with a trace. Compare that with actually ending up with bad state in golang if errors are accidentally ignored or overwritten (I've seen it happen several times). golang errors are strictly inferior.
- stickfigure 6y agoAnd in practice, with Java, C#, etc programs, there's a high level catch that prevents anything terrible from happening. Http requests return 500, UI threads show an error dialog, etc. In almost all business processing, thanks to the magic of transactions, you never end up in a bad state.
- aboodman 6y agoOuch. Super sorry about the shitty code in the free project you built your business on ;-). Anyway, this was a point of huge debate early on in the development of Noms. Some team members just could not accept the constant litter of `if err != nil` no matter how many times I repeated that Rob Pike says it's OK. It goes against deeply held beliefs that all programmers internalize early on, for good reason. It’s probably why some parts of Go internally have also used panics for flow control (the JSON decoder, famously), and just convert them to errors at the boundaries. This was our plan, but we were not careful about protecting all the goroutine launches. As I said elsewhere in the thread I think we would have welcomed working together on this if the Dolt folks had wanted to.
- throw_m239339 6y ago> that Rob Pike says it's OK. I should say, Rob Pike didn't put in the language the features that would have helped alleviate the pain of writing 50,000 times the exact same statement littering Go code bases like a plague. Go errors are purely a convention that is no better than C style error code returns. Not good enough in whatever year Go was designed. There are solutions to that issue that are much more composable than that (options, sum types...). People come to Go for performance and concurrency (although context is another one of these tacked on horrors) and they leave the language because of the crazy ceremonial boilerplate it incurs.
- vii 6y agoRob Pike wrote this about handling errors https://blog.golang.org/errors-are-values https://blog.golang.org/errors-are-values This is like an option type but manually built. Go is painful if you don't want to write high-quality heavily exercised production code. If you do, then you should be considering each error condition. Most code doesn't need to worry about error handling as it will run under close supervision on at most one machine over its lifetime. Go is a nuisance for that.
- apta 6y ago> Go is painful if you don't want to write high-quality heavily exercised production code. That's the excuse that the golang authors give. The fact of the matter, golang is also extremely annoying when writing "high quality production code". golang errors are error-prone, and on more than one occasion we've had instances where errors are mistakingly ignored. This is much worse than exceptions where they have to be explicitly swallowed, otherwise they'd automatically bubble up.
- joshuak 6y agoOr you could have just caught panics at the top, and transformed them to errors. https://github.com/dre1080/recovr https://github.com/dre1080/recovr That's what we do. Well we always use errors, but we can't be sure the packages we use won't panic.
- whateveracct 6y agoGo programmers also tend to have terminal systems brain, so the runtime cost of panic tends to bother them to their core :)
- erik_seaberg 6y agoIf they used unwind tables for panic, it would be cheaper than a deeply nested stack of mispredicted “if err != nil” branches. But according to https://dr-knz.net/go-calling-convention-x86-64.html https://dr-knz.net/go-calling-convention-x86-64.html they don’t, probably because you can randomly defer stuff anywhere and it isn’t statically scoped.
- zachmu 6y agoNo, that's not possible. A panic must be recovered in the goroutine in which it occurs. An unrecovered panic in any goroutine kills the entire process, not just the offending goroutine. There is no way to top-down wrap an entire go process in a recover block to keep a panic from killing your process. You have to do it in each and every goroutine.
- joshuak 6y agoTrue, which is one of the reasons why the practice of launching goroutines inside of packages is discouraged. Granted its sometimes unavoidable and some package maintainers just didn't get the memo, nevertheless when deciding on a package to use it's much easer to find dubious goroutines, than assessing if every potential panic has been handled correctly. Usually easer to fix too if warranted.
- dnautics 6y agoAnd this is why the equivalent of panics have well defined (and customizeable) blast radii in the erlang-vm languages. This had been solved, fifteen years before go. I understand why java doesn't have this (it's legacy, from the era of erlang). I can't understand why Rob pike didn't steal that idea from erlang.
- erik_seaberg 6y agoGo is “a direct descendant of Limbo,” and seems to steal very little that was invented after Plan 9 in the early 1990s. I was about to say UTF-8 is an exception but they themselves brought us that in 1992.
- apta 6y ago> I understand why java doesn't have this It's getting it in Project Loom as far as I understand (hierarchical/supervisor processes). It goes to show how badly thought out golang is when it comes to language design.
- dnautics 6y agoyes, it is (finally) happening in Project Loom. I don't consider that delivered yet.
- nanoscopic 6y agoI agree that adding error checking at every possible error location and then passing up those errors is tedious, but it is a direct result of Golang essentially being a "modern C". In the case you describe it sounds like it was particularly painful due to the multi-threaded nature of the software. You didn't call it out directly but I feel like the inability of Golang to do polymorphism makes it more difficult. If the result of something is simply a message, and that message can be either a normal data type or an error, then you don't need to always additionally return an optional error. This is why I prefer the idea of message passing languages over direct procedural languages. It is still possible to do this somewhat in Golang using channels and/or queues, channels can tend to get clogged and freeze up in my experience. I've had good experiences using Mangos ( Golang nanomsg implementation ). If you use inproc queues, you can do multi-threading in a language portable way. Then, if you decide to replace a processing component with something other than Golang, it is relatively easy to do so.