Because I didn't have much time before the final submission, I just put the initial call in a try catch block and threw an exception to indicate successful completion.
Because I didn't have much time before the final submission, I just put the initial call in a try catch block and threw an exception to indicate successful completion.
The alternative is every single function has to return a boolean, along with whatever else it would return, which is true when you have found a solution, and you then return straight away -- effectively just reimplementing exceptions by hand, which doesn't feel like a useful use of my time.
I love Go, but its error handling leaves so much to be desired. I even have an Emacs macro that inserts "if err != nil" for me. Also very easy to make a mistake in the rare case where you have to write "if err == nil"; my eyes just skip over any line that includes the words "if", "err", and "nil", as if it was some attention-hungry inline ad.
Rust started off chatty, but soon introduced the "?" syntax, which works perfectly well in the 99% case. Go had a couple of similar proposals, but "keep if err != nil" just... won.
Not without its related traits and whatnot. Without those you have the same all the same problems the Go proposals keep running into. Trouble is that it is not yet clear what the Go equivalent is to those related features.
However, the attempts to figure that out keep coming. Ian Lance Taylor (of generics fame) recently implemented the latest proposal to try it out, although it seems it too has failed, but suggests that things are inching closer to something usable when the initial details were able stand up to basic scrutiny. Nothing has "won" yet.
It’s fine that golang has made missteps along the way and course corrects. Or if people realize that some hoped-for development doesn’t come to pass, but the current state of things is acceptable.
But the number of times it feels like we’re just told things were always this way, or this was always the goal, or actually having 2/3s of the language being redundant boilerplate is a good thing (it’s “explicit”), or actually they always intended to have generics because it’s important for library authors, or actually systems programming always meant small network services, or actually abstraction is bad unless it’s coincidentally the exact level of abstraction that golang ended up with, or… on and on and on.
It’s exhausting and it’s not a good look on the community.
There was a time when generics were not even on the table. I'm pretty sure I remember an old talk by Rob Pike where he says that much.
People can change their mind as they learn more about the problem space; that should be tolerable.
No such development has occurred. The state of the art remains three lines of boilerplate around most function calls in practice.
And honestly, if the mindset was: hey, you know what, this isn’t great but it’s what we’ve ended up with, it isn’t the end of the world, and maybe we’ll crack the nut and improve things down the line… I think a lot of golang’s detractors would nod and everyone would move on.
Instead, everyone clings to: three lines of mostly-identical error handling around every function call is optimal, I prefer it this way, all of this extra code is “explicit” so it’s an inviolable good, we’ve always been at war with Eastasia.
As someone who is more than happy to point out all the things that annoy me about the languages I prefer to use, it feels at times like entire community wants to pretend that there aren’t any flaws or downsides with the language.
> it feels at times like entire community wants to pretend that there aren’t any flaws or downsides with the language.
Yeah, the delusion of version 2.0 perfection is strong from Golang thought leaders. It is nauseating to read about. Like the whole resistance to generics, then finally giving in, then finally saying "Yeah, we definitely need these." So... the last 8(?) years of blogging against generics... what about that? Another comment below used the phrase "gas-lighting the users" which seems appropriate here.Deeper: This will be controversial to some readers here. I wonder if the reason why the "entire community" resists criticism so fiercely is that Rob Pike has a very public profile and "infinite Internet (reputation) points", so no one can beat that final boss. I'm not saying that Rob Pike would use his Internet boss powers to kill off any critics, but I do think it does repress some critics. Also, his style and opinions are very strong.
All said, as a non-Golang writer, but avid reader, I am still very impressed by how carefully that Golang was developed. It could have gone so much worse (C++? JavaScript?), or the community been much more toxic/unwelcoming, e.g., Rust. Overall: It is a huge win for current and future programmers.
What makes you think that? The Go team is clearly working on trying to crack the nut. There is, as of about a month ago, even now an exploratory implementation: https://github.com/golang/go/discussions/71460 It is not an easy nut to crack. Many serious proposals have failed for good reasons. But it is abundantly apparent that the effort is there and ongoing.
The "golang detractors" aren't acting rationally. If you watch carefully you will see that most of the time they don't even understand their detraction points, indicating that they are simply repeating what they saw elsewhere. The unfortunate reality is that they aren't looking to contribute anything meaningful, they are simply trying to be funny and they will continue to believe it is funny until "You idiot, Go already has that" can be said and manages to wear them down.
> three lines of mostly-identical error handling around every function call is optimal
To be fair, while I am sure we could do better, I am not sure we have found it yet. I do my programming in various languages with all these fanciful error handling semantics and it is not good. I regularly wish those languages' idioms had settled on something like if err != nil over what they ended up with. It is not great, but better than the rest. But it is encouraging that smart minds are working hard trying to find better.
The one exception to this trend has been generics. I think it was an inevitable addition to the language, but there are still a lot of holdouts who argue it wasn’t necessary. I think this is probably because it’s more important for library authors than app developers. But it does remain by far the most divisive update to the language.
> The "golang detractors" aren't acting rationally. If you watch carefully you will see that most of the time they don't even understand their detraction points, indicating that they are simply repeating what they saw elsewhere.
I personally don’t think I’ve seen a lot of that. At this point it’s endemic enough that there’s a small and shrinking number of engineers each year who haven’t spent time in it.
> To be fair, while I am sure we could do better, I am not sure we have found it yet.
Everything below here is a more or less reasonable take (even if I have mild disagreements), and I think a lot of people would feel less likely to snipe at the language if more people expressed opinions like this.
Where is this mantra emanating from, exactly? Go officially became community driven in 2017. If the community didn't seek this, nobody, especially not the core team, would be working on it. Actions certainly do not support your idea.
> there are still a lot of holdouts who argue it wasn’t necessary.
Of course. Obviously it isn't necessary, or even beneficial, for all programming problems. The software industry is quite broad and developers are working on all kinds of different things. One is only going to speak from their own experience. It is all they know. And I expect error handling is contentious in much the same way because of it being something that crosses many different types of programming areas in different ways.
In fact, despite what may seem contrary to what I said earlier, there are classes of of software problems where you do think about errors differently. For example, letting the program close with a message and letting a human deal with whatever went wrong is a perfect solution to many error-related problems and language constructs that make that easy is wonderful. In those cases the fancy error handling semantics are quite appreciated.
Naturally, my assertion that something like "if err != nil" being the best we've got comes from the type of software I normally find myself needing to write. If you work on different types of problems, you're bound to have a different perspective. Expecting to find agreement here is much like expecting basketball players and baseball players to find agreement about what kind of ball they should share. But there is no need to.
It's abundantly clear where the actual Go community stands on this. They have a visible interest in seeing what can be done; to try and find out if there is a better way. That does not guarantee success, but the desire to try is undeniable.
One example, if I may: the errors.As function is far from ergonomic. It would have been much better if generics had come to the language before that function was added to the standard library. Modern alternatives exist: https://pkg.go.dev/github.com/jub0bs/errutil
(rust, meanwhile, had macros, and people settled on the try! macro fairly quickly, which is basically just bundling up 'if err != nil' into a smaller package, and that eventually turned into '?' because try! was still a bit too unwieldy. Go doesn't have an way to do the same)
addendum: Having read the blog post, it seems like it's basically arguing for interfaces which essentially buffer error reporting. I've written code that works like this before, and it doesn't really deal with control flow well at all: it's basically only a solution for the case of having a straight-line set of function calls, and some interfaces are commonly used like this, but it's only a fraction of them and you introduce more likelihood of errors if you then try to use them in more complicated situations (imagine his proposed option but you want to make a decision based on a value in the middle, or run a loop. It either stops working entirely or you have to decide on a 'safe' fake default value to return in the case of an error fall-through that doesn't break the logic, which is usually impossible.
Stack traces in other languages do this in a way, but are often unreadable and require manually inspecting each function in the trace to figure out the reason of the bug. Even worse if some function in the middle catches the original exception and returns another exception, completely devoid of the former's context and information.
Even worse if you're using any kind of framework that renders stack traces useless ala async Rust or Java Spring. All you get is a bunch of noise from framework and almost nothing from your program.
In Go, most of the errors I get are chains of carefully written messages, e.g. "request failed: write file: create: directory does not exist". And given that errors are just values and not tied to a stack, they can internally be passed through channels in all kinds of complex goroutine pipelines, and not lose any information.
Go basically makes your life worse, until you get used to writing meaningful context-relevant messages and thinking about errors. Which in turn makes your life a lot easier when diagnozing and debugging an issue.
The problem with most languages here is the name "exceptions" implying it's for exceptional scenarios, but without any substitute for good non-local control flow.
Rust: Return Some(value) or None