4 ms·
>the error handling was one of the many positive features. sounds good on paper, but seeing "if err!=nil" repeated million times in golang codebases does not c
by slt2021 3y ago
>the error handling was one of the many positive features.
sounds good on paper, but seeing "if err!=nil" repeated million times in golang codebases does not create positive impression at all
- slt2021 3y agogolang keyboard ftw https://pbs.twimg.com/media/DCIF7-2W0AEAv9c.jpg https://pbs.twimg.com/media/DCIF7-2W0AEAv9c.jpg
- Mawr 3y agoYes but the impression is largely superficial. The error handling gets the job done well enough, if crudely.
- FuckButtons 3y agoThe ability to quickly parse, understand and reason about code is not superficial, it is essential to the job. And that is essentially what those verbose blocks of text get in the way of.
- Mawr 3y agoSure, I just don't think it's that significant. Humans don't read/parse code character-by character, we do it by recognizing visual patterns. Blocks of `if err != nil { }` are easy to skip over when reading if needed.
- bbkane 3y agoI agree, though I was really surprised to learn this when reading Go code. Much easier to skip over than I was expecting it to be
- IshKebab 3y agoThe idea that error handling is "not part of the code" is silly though. My impression of people that hate Go's explicit error handling is that they don't want to deal with errors properly at all. "Just catch exceptions in main and print a stack trace, it's fine." Rust's error handling is clearly better than Go's, but Go's is better than exceptions and the complaints about verbosity are largely complaints about having to actually consider errors.
- Capricorn2481 3y ago> The idea that error handling is "not part of the code" is silly though. My impression of people that hate Go's explicit error handling is that they don't want to deal with errors properly at all. "Just catch exceptions in main and print a stack trace, it's fine." I'm honestly asking as someone neutral in this, what is the difference? What is the difference between building out a stack trace yourself by handling errors manually, and just using exceptions? I have not seen anyone provide a practical reason that you get any more information from Golangs error handling than you do from an exception. It seems like exceptions provide the best of both worlds, where you can be as specific or as general as you want, whereas Golang forces you to be specific every time. I don't see the point of being forced to deal with an "invalid sql" error. I want the route to error out in that case because it shouldn't even make it to prod. Then I fix the SQL and will never have that error in that route again.
- IshKebab 3y agoThe biggest difference is that you can see where errors can happen and are forced to consider them. For example imagine you are writing a GUI app with an integer input field. With exception style code the overwhelming temptation will be to call `string_to_int()` and forget that it might throw an exception. Cut to your app crashing when someone types an invalid number. Now, you can handle errors like this properly with exceptions, and checked exceptions are used sometimes. But generally it's extremely tedious and verbose (even more than in Go!) and people don't bother. There's also the fact that stack traces are not proper error messages. Ordinary users don't understand them. I don't want to have to debug your code when something goes wrong. People generally disabled them entirely on web services (Go's main target) due to security fears.
- Capricorn2481 3y ago> But generally it's extremely tedious and verbose Is it? In my experience it's very short, especially considering you can catch multiple errors. Do my users really need a different error message for "invalid sql" vs "sql connection timeout?" They don't need to know any of that. > There's also the fact that stack traces are not proper error messages I would say there's not a proper error message to derive from explicitly handling sql errors. Certainly not a different message per error. I would rather capture all of it and say something like "Something went wrong while accessing the database. Contact an admin." Then log the stack trace for devs
- marcus_holmes 3y agoAs an experienced Go dev, this is literally not a problem. Golang code has a rhythm: you do the thing, you check the error, you do the thing, you check the error. After a while it becomes automatic and easy to read, like any other syntax/formatting. You notice if the error isn't checked. Yes, at first it's jarring. But to be honest, the jarring thing is because Go code checks the error every time it does something, not because of the actual "if err != nil" syntax.
- LinXitoW 3y agoJust because you can adapt to verbosity does not make it a good idea. I've gotten used to Javas getter/setter spam, does that make it a good idea? Moreover, don't you think that something like Rusts ? operator wouldn't be a perfect solution for handling the MOST common type of error handling, aka not handling it, just returning it up the stack? val, err := doAThing() if err != nil { return nil, err } VERSUS val := doAThing()?
- foldr 3y agoI personally have mixed feelings about this. I think a shortcut would be nice, but I also think that having a shortcut nudges people towards using short-circuit error handling logic simply because it is quicker to write, rather than really thinking case-by-case about what should happen when an error is returned. In production code it’s often more appropriate to log and then continue, or accumulate a list of errors, or… Go doesn’t syntactically privilege any of these error handling strategies, which I think is a good thing.
- gwd 3y agoThis. Golang's error handling forces you to think about what to do if there's an error Every Single Time. Sometimes `return err` is the right thing to do; but the fact that "return err" is just as "cluttered" as doing something else means there's no real reason to favor `return err` instead of something slightly more useful (such as wrapping the err; e.g., `return fmt.Errorf("Attempting to fob trondle %v: %w", trondle.id, err)`). I'd be very surprised if, in Rust codebases, there's not an implicit bias against wrapping and towards using `?`, just to help keep things "clean"; which has implications not only for debugging, but also for situations where doing something more is required for correctness.
- sethammons 3y agoI find that knowing where my errors may come from and that they are handled is essential to my job and missing all that info because it is potentially in a different file altogether gets in the way
- lelanthran 3y ago> sounds good on paper, but seeing "if err!=nil" repeated million times in golang codebases does not create positive impression at all Okay, but other than exceptions, whats the alternative?
- nindalf 3y agoThe ? Operator in Rust?
- dureuill 3y agoMore than just that, Result in general also prevents from accessing the value when there is an error and accessing an error when there is a value.
- throw-the-towel 2y agoThe absence of that safeguard in Go is a feature. It's used when the error isn't that critical and the program can merrily continue with the default value. Of course, this is also scarily non-explicit.
- lelanthran 3y agoGood point. I only briefly tried Rust and was turned off by the poor ergonomics; I don't think (i.e. open to correction) that the Rust way (using '?') is a 1:1 replacement for the use-cases covered by Go error management or exceptions. Sometimes (like in the code I wrote about 60m ago), you want both the result as well as the error, like "Here's the list of files you recursively searched for, plus the last error that occurred". Depending on the error, the caller may decide to use the returned value (or not). Other times you want an easy way to ignore the error, because a nil result gets checked anyway two lines down: Even when an error occurs, I don't necessarily want to stop or return immediately. It's annoying to the user to have 30 errors in their input, and only find out about #2 after #1 is fixed, and #3 after #2 is fixed ... and number #30 after #29 is fixed. Go allows these two very useful use-cases for errors. I agree it's not perfect, but with code-folding on by default, I literally don't even see the `if err != nil` blocks. Somewhat related: In my current toy language[1], I'm playing around with the idea of "NULL-safety" meaning "Results in a runtime-warning and a no-op", not "Results in a panic" and not "cannot be represented at all in a program"[2]. This lets a function record multiple errors at runtime before returning a stack of errors, rather than stack-tracing, segfaulting or returning on the first error. [1] Everyone is designing their own best language, right? :-) I've been at this now since 2016 for my current toy language. [2] I consider this to be pointless: every type needs to indicate lack of a value, because in the real world, the lack of a value is a common, regular and expected occurrence[3]. Using an empty value to indicate the lack of a value is almost certainly going to result in an error down the line. [3] Which is where there are so many common ways of handling lack of a value: For PODs, it's quite popular to pick a sentinel value, such as `(size_t)-1`, to indicate this. For composite objects, a common practice is for the programmer to check one or two fields within the object to determine if it is a valid object or not. For references NULL/null/nil/etc is used. I don't like any of those options.