6 ms·
Does this look like a design mistake or a bit of oversight? There is no excuse why one should have to do result, err := Foo() if err != nil { ...
by mrkgnao 9y ago
Does this look like a design mistake or a bit of oversight? There is no excuse why one should have to do
result, err := Foo()
if err != nil {
...
}
over and over again in a language designed after 2000. The usual argument is that Go's simplistic design "reduces complexity", yet explaining something basic as why the error handling system doesn't behave the way one expects needs you to know how the compiler represents interface types.
The next decade will see Go adding in most or all the complexity real-world software asks for, without ever admitting that maybe it should've been supported from the beginning without the hacky workarounds.
> Honestly if you aren't a skilled enough programmer to navigate the nuances of any particular language then you really are no better than kids[...]
Even though the bit in italics is pretty much the opposite of the "Go/JS pitch", I'll bite.
Sure, learning to code at a high level means you need to take time to learn things (which is the opposite of the pitch). I just don't get why teaching yourself to "navigate the [brokenness]" of a language that was out-of-date the day it was released is preferable to learning to write in an expressive language that won't artificially handicap you or provide you with an arsenal of footguns.
In all the time you were casting to and from interface{}, you could be exploring and using powerful and practical new ideas that make it less likely you'll suffer for failing to check one of those "err"s.
- laumars 9y ago> Does this look like a design mistake or a bit of oversight? Honestly, I don't mind error handling in Go. I've used a wide variety of languages in production systems (I've lost count but it's more than a dozen) and I've found Go to be surprisingly good at giving detailed, context aware breakdowns of where issues arise and allowing me to easily handle them. Sure there are a thousand different ways to do this and Go picked the ugliest, but in spite of that I've found it to be surprisingly effective - even in the more complex projects I've written like murex (my alternative UNIX $SHELL) and the odd Linux FUSE file system I've written to scratch a particular itch. In fact for as many complaints like yours I've read there are also as many seasoned developers complementing Go's error handling. So I really think that particular issue is more a matter of personal taste rather than poor language design. However I'm _not_ going to defend the nil thing nor how interface{}'s are (ab)used as an alternative to generics. Those _are_ just bad design choices. But for all of Go's sins, I still find myself more productive writing Go code than I have in any other language for a long time (probably since writing Pascal in Borland's Turbo Pascal back in the 90s). Hence why I defend Go. I can understand idealistic opinions about language design (Go is opinionated too after all) but frankly what really matters is a developers ability to get an idea into something executable. And I feel a lot of the complaints about Go really miss the point about how productive that language is to a great many people and without sacrificing too much control to be useful in a practical sense.
- sagichmal 9y agoThe error handling idiom in Go is one of its strongest properties. Forcing developers to accommodate the error path inline and at each callsite makes code resilient and robust. It would stand to benefit from a Maybe feature, but even as-is it's a huge net positive versus e.g. exceptions. People who complain about it don't grok the Go ethos. That's fine, it's not for everyone.
- dullgiulio 9y agoYou are doing it wrong. You should check if there is an error (not the other way around) and return early. How about you study the language a bit more in depth (including estabilished idioms) before pontificating about it?
- mrkgnao 9y ago> estabilished idioms I'll note that The Fine Article is about why one of those established idioms confuses newcomers. Even better, it bites people because the type of an interface needs to be nil for something to work. (Insert appropriate expression of astonishment here.) Enforcing patterns hiding inadequacies in the implementation works less well than one would imagine, e.g. look at all the languages that Go sought to improve upon and the baggage of "design patterns", GoF-alikes, etc. that they brought with them. > return early I was just going off what I found at https://blog.golang.org/error-handling-and-go https://blog.golang.org/error-handling-and-go. I assume you meant this (in Go-ish pseudocode)? result, err := Foo1() if not err { Panic(err) } result2, err2: = Foo2(result1) if not err2 { Panic(err2) } This might allow you to skip the nesting of blocks, but why would you do this when multiple languages exist where you don't have to thread around error messages everywhere? For instance, result1 <- foo1 result2 <- foo2 result1 (Yes, that's Haskell syntax, but you can do things with a similar lack of pain/verbosity/error-prone-ness in many languages.)
- dullgiulio 9y ago1. Your assumption is wrong, I definitely didn't mean panic. 2. I think the arrow means assignment in Haskell and you are just referring to monadic errors? To use them the same way proper error handling is done in Go, you would just have more nesting and multiple unwraps, which is marginally different than Go syntax (but definitely with more compiler checking.) The arrow syntax in Go is used by channels.
- mrkgnao 9y agoApologies. In any case, monadic errors in Haskell allow you to make "failing early" automatic. Even a simple use of optional types can make a difference. For instance, here you're failing with the same error every time, like here: a, err := squareRoot(x) if err { handle(err) } b, err := log(a) if err { handle(err) } c, err := log(b) if err { handle(err) } you can just use an optional ("Maybe") type: write a, b, and c with types like a :: Double -> Maybe Double and then do a <- squareRoot x b <- log a c <- log b If the computation of a fails, the whole computation fails. The compiler takes care of all the error-checking plumbing. I think the ergonomics of this common kind of situation are really suboptimal in Go, which to my knowledge doesn't support anything remotely similar.