4 ms·
One of Go's problems, relative to Rust, is that error values of functions can be ignored. In rushed corporate code, this means that developers will inevitably k
by OutOfHere 2y ago
One of Go's problems, relative to Rust, is that error values of functions can be ignored. In rushed corporate code, this means that developers will inevitably keep ignoring it, leading to brittle code that is not bulletproof at all. This is not an issue in Rust. As for static analyzers, their sane use in corporate culture is rare.
- Hendrikto 2y agoYou can ignore errors in Rust too, just like any language. And people do, just like with any language.
- treyd 2y agoIn Rust you have to explicitly state that you're ignoring the error. There is no way to get the value of an Ok result without doing something to handle the error case, even if that just means panicking, you still have to do that explicitly. In Go you can just ignore it and move on with the zeroed result value. Even the error the compiler gives with unused variables doesn't help since it's likely you've already used the err variable elsewhere in the function.
- foobarbaz33 2y agoTrue, but running errcheck will catch cases where you accidentally ignore the error. Maybe not as good as having it built-in to the language like Rust, but the goal of error check safety is achieved either way. And there's a few cases like Print() where errors are so commonly ignored you don't even want to use the "_" ignore syntax. Go gives you the poetic license to avoid spamming underscores everywhere. error linters can be configured to handle a variety of strictness. For non-critical software, it's OK to YOLO your Print(). For human-death-on-failure software you may enforce 100% handling, not even allowing explicit ignore "_" (ie become even stricter than Rust language default)
- sapiogram 2y agoerrcheck will not catch everything. For example, it will not stop you from using a value before checking the error, as long as you check the error later. I've personally broken things in production because of that corner case, despite (usually) being very careful about error handling.
- Cthulhu_ 2y agoNo language or linter will be perfect, and IMO unit tests should be written for what the compiler doesn't do for you. In this case, your unit tests missed code paths, which should show up in a code coverage analysis or fuzz test.
- treyd 2y agoRich type systems like Rust's do completely prevent this type of mistake. You don't need unit tests to ensure that the error condition is handled somehow because we statically assert it within the type system of the language.
- 9rx 2y agoHandling an error is pointless if you don't handle it correctly, and for that you need unit tests anyway, so you still need to write the tests and once you've done that it is impossible to encounter the mistake without knowing it no matter how you slice it. But your editor can give some more realtime feedback instead of waiting for your tests to run, so I guess that's cool.
- bigstrat2003 2y agoThat's only the case if you consume the return value. It's perfectly legal (though it gives you a compiler warning) to call a function that returns a Result and never check what actually happened.
- Cthulhu_ 2y agoThe question that's needed to ask is whether you'd like the language or its ecosystem to guard against these things, or whether you are a decent and disciplined developer. For example, Go's language guards against unused variables or imports, they are a compiler error. Assigning an `err` variable but not using it is a compiler error. But ignoring the error by assigning it to the reserved underscore variable name is an explicit action by the developer, just like an empty `catch` block in Java/C# or the Rust equivalent. That is, if you choose to ignore errors, there isn't a language that will stop you. Developers should take responsibility for their own choices, instead of shift blame to the language for making it possible.
- lexicality 2y agoWhenever I see people appealing to developers to be "disciplined" I think about those factory owners protesting that they wouldn't need guards or safety rails if their workers were just more careful about where they walked. If developers were more disciplined Go wouldn't need a garbage collector because everyone would just remember to call `free()` when they're done with their memory...
- dontlaugh 2y agoHowever, you can make a call without assigning the result at all, entirely ignoring it. That isn’t possible in Rust.
- amenhotep 2y agoRust genuinely will stop you, though. You can't take a Result<T> and get an Ok(T) out of it unless there's no error; if it's an Err then you can't continue as if you have a T. It doesn't force you to do something productive with the error, but you can't act like it was what you wanted instead of an error.
- TheDong 2y agoYeah, but now you have to teach your programmers about generics and applicative functors. I'm just a simple country gopher, but my brain isn't capable of understanding either of those things, nor are any of my coworkers, nor any of the people we hire, and it doesn't really matter how theoretically "nice" and "pure" your generics and results and monads are if us real professional programmers get confused by them. Errors need to be explicit values, not magic monads. 'if err != nil' is good and easy to think about, 'res.map().or_else()' is incomprehensible line noise no normal programmer can understand. https://paulgraham.com/avg.html#:~:text=The%20Blub%20Paradox https://paulgraham.com/avg.html#:~:text=The%20Blub%20Paradox
- crackrook 2y agoIn my view the core problem is the lack of proper sum types. Using product types to represent results seems fundamentally wrong; the vast majority of procedures only have 2 possible outcomes -- they fail or they don't -- 2 of the 4 outcomes that the type system permits are (almost always) nonsensical. I don't see a good reason to design a modern language in this way, it feels less like an intentional design choice and more like a hack.
- Thaxll 2y agoRust values can be ignored as well. There is no language to my knowledge that prevent you from ignoring values.
- k_g_b_ 2y agoAny language that implements linear types has values that can't be ignored and need to be passed to some "destructor" (could just be a deconstruction pattern assignment/similar). Examples: Austral, some of these https://en.m.wikipedia.org/wiki/Substructural_type_system#Programming_languages https://en.m.wikipedia.org/wiki/Substructural_type_system#Pr... in particular at least ATS, Alms, Granule, LinearML Though most haven't gone beyond research languages yet.
- liampulles 2y agoI think the issue here is not so much that errors can be ignored in Go (sometimes one doesn't care if something worked, they just want to try), it's more that errors can easily be ignored by accident in Go. I definitely have seen that, and sometimes have done that myself, but I have to say it hasn't happened in a while since the linting tools have improved