10 ms·
if err := http.ListenAndServe(":8080", nil); err != nil { panic(err) } I've seen this kinds of stuff in PHP database APIs, and I've seen how much small
by romaniv 14y ago
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
I've seen this kinds of stuff in PHP database APIs, and I've seen how much smaller and more readable the codebase becomes with proper use of exceptions. This is a huge downside of Go.
- drivebyacct2 14y agoConversely, this is a huge upside of Go. I enjoy the explicit error handling. It's a very conscious decision. There is panic/recover style "exceptions" but that's for truly exception states and not just error states. It seems a rather bad example anyway, not sure why I'd prefer: try { http.ListenAndServe(":8080", nil); } catch(ServeException se) { // handle se } over the Go alternative.
- masklinn 14y agoIn this precise case, the alternative would be: http.ListenAndServe(":8080", nil) the uncaught exception would kill the task because, really, what is your http server going to do aside from exit if it can't serve? Not sure why you added a bunch of lines which end up doing the exact opposite of what the original code does.
- tomjen3 14y agoLog the error to the logging system (may also fail) and try again, upto a specific number of times?
- romaniv 14y agoExactly. It horrifies me that there are still programmers who don't understand this after so many years of OOP advocacy. The benefits of a properly designed (not Java-like, but C# or PHP like) exception system stems from the fact that in the wast majority of cases you don't need to catch exceptions right away. Most exceptions can be handled in a few centralized locations higher up the stack. If you have 10 calls to ListenAndServe, this means having 10 times less exception handling code. Moreover, when you design a library and the users actually care about errors, exceptions save you from needing to pass your error codes up the call chain from deeply nested methods.
- zemo 14y ago>If you have 10 calls to ListenAndServe ListenAndServe blocks forever. If you have 10 calls to ListenAndServe, it's implied that you're in 10 different, concurrently running processes (goroutines). A panic, in Go, does not cross a goroutine boundary. If, in imaginary parallel universe Go with exceptions, exceptions did cross goroutine boundaries, then one goroutine could crash another goroutine. The point of Go is to be able to sensibly write stable, concurrent programs with compile-time safety. Exception-based error handling would be a mess with Go's concurrency model. In practice, you would only call ListenAndServe 10 times if you were listening on 10 different ports, because you had 10 different projects on the same server. That's a perfectly realistic situation. Now consider that one site has an error and throws an exception. Should all the other sites go down? Error handling in Go is admittedly tedious, but when you work with the language for a bit you'll start to understand why they chose to design it in that manner.
- flogic 14y agoIf Panic doesn't cross goroutine boundaries, why should exceptions?
- drivebyacct2 14y agoThe whole point is, it wouldn't make sense for them to cross goroutine boundaries, but the pleasure of Go is the ease with which you can use goroutines. Thus, in a lot of places where people would lazily use exceptions to aggregate potential errors, you would be unable to because the exception is occuring in a goroutine. Which is why there are other nice ways of communicating such states in go that go hand in hand with handling errors at their occurrence. If you find an error in a goroutine, you can signal that on a channel, return and wait for a new goroutine to be restarted in place of the errored one.
- drivebyacct2 14y agoSo because you can't think of an alternative, there should be no way of handling a scenario where, say, maybe that port is already in use? Again, the explicitness is by design. My "handle" code would be checking the failure and acting on it: trying another port, logging a message, sending an email telling me my server isn't starting. I doubt the existence of a real world app that really fires up an HTTP server and blindly dies without so much as logging to indicate failure.
- masklinn 14y ago> So because you can't think of an alternative, there should be no way of handling a scenario And more strawmanning, great. Of course there is a way to handle failure: catch the bloody exception. Which is completely unlike what the original code does, hence your original comment being a (not very original) strawman.
- thebigshane 14y agoIf you don't care about the error (because you're just going to let the task die anyway). Then in Go, wouldn't you just write... _ := http.ListenAndServe(":8080", nil) ?
- drivebyacct2 14y agoYou get a syntax error, "no new variables on left side of :=". You could do: _ = http.ListenAndServe(*port, nil) But why would you? Just omit it entirely. The only time you need to explicitly ignore errors is in multiple returns. consider: http://play.golang.org/p/o8vLQQmRvp http://play.golang.org/p/o8vLQQmRvp which would be fixed like: http://play.golang.org/p/DH0j1cwRqW http://play.golang.org/p/DH0j1cwRqW But yes, since ListenAndServe is normally used to block before main() returns, you could let it fail and terminate. (But you'd probably want to exit with a non-zero value, at least I would).
- rogerbinns 14y agoGo has committed the same faux-pas as C. It is true it won't make a difference for the truly diligent programmer, but not everyone is, and even the best can be off at 3am. The simple proof that Go's approach is wrong is to look for all the Hello World examples. I have yet to find one that looks at the error return of the println, just like none look at the return of C's printf. Your example is because of Java's use of checked exceptions. Exceptions are fine - checked exceptions are stupid and cause a different class of programming errors.
- thraxil 14y agoSometimes the correct approach is to ignore the error. If printf or equivalent in a hello world program can't print to stdout, what should it do instead of crashing? Send an email? I don't think I've ever seen a hello world for a language with exceptions (checked or not) that actually handled an exception from printf either.
- 0xABADC0DA 14y agoSomething like this: # /bin/echo "Hello World" >&- /bin/echo: write error: Bad file descriptor You get this kind of thing for free with exceptions.
- papaf 14y agoThe simple proof that Go's approach is wrong is to look for all the Hello World examples. I have yet to find one that looks at the error return of the println, just like none look at the return of C's printf. The builtin println does not return a value. As stated in the language specification: http://golang.org/ref/spec#Bootstrapping http://golang.org/ref/spec#Bootstrapping
- drivebyacct2 14y agoYou're also not meant to use those, they're generally discouraged. rogerbinns is right, fmt.Println() does indeed return an error value. I still don't understand the argument. Println() can fail. That's why it is able to return an error. You can choose to ignore it, that's fine. If it's something that you're worried about failing, then it's worth the "effort" to handle the error where and when it happens. I guess ultimately, all of this stuff is such a non-issue. It's a cliched response to a lot of Go criticism, but acutally write something in it. Armchair critics would have you believe that exceptions and generics missing is the end of the world. Number one, it's not. Number two, these simplifications exist for a reason. One of Go's guiding principles is minimizing magic that is not visible or explicit. (That's why new/make exist, no exceptions, no generics). It eases development speed, code clarity and compile times.
- 0xABADC0DA 14y agoAlso OP missed the ever-present: defer s.Close() I assume it should be: defer func() { err := s.Close(); // handle error }(); But how do you handle the error? Say the method returned successfully until the defer, do you then 'unreturn' the success return value and set the error return value? Return both a success and error value? Or say it returned failure, do you trash that value and replace it with the s.Close() error? Create some ad hoc meta error that contains both? Error handling in golang is a total mess all by itself... then you throw panic/recover into the mix and it just gets worse. EDIT: forgot hacker news readers get offended by "Google Go" so changed to golang.
- jlgreco 14y agoThe language is "Go", not "Google Go".
- oinksoft 14y agoPresumably code affected by an error state is also affected by a success state. The reasonable place to take action based on this result is directly in the async function, or otherwise in some callback.
- scarboy 14y agoYou can modify the state by using named return values. func ContrivedExample() (file *os.File, err error) { file, err = os.Open("something.txt") defer func() { if err = file.Close(); err != nil { file = nil } }() return }
- wonderzombie 14y agoThat is incorrect. session.Close() doesn't return an error. Still, there are cases where Close() methods return an error, so let's pretend it does. You're in the mess you describe above because you insist on making the wrong choice up front, which is to use defer for something which is non-trivial. If your error handling is so important, why would you bury it in an anonymous function? That's a bad decision in any language. Write it out explicitly. People will notice and give it due care because if it weren't special, you'd use defer. Look at sql.go in the standard library: http://golang.org/src/pkg/database/sql/sql.go?s=5813:5840#L202 http://golang.org/src/pkg/database/sql/sql.go?s=5813:5840#L2.... You can see that the error handling in such as putConn() and Close() do not use defer because it's the wrong choice. Conversely, if you grep the codebase for defer, there are plenty of places where it is useful.
- zeeboo 14y agoNot surprisingly, I completely disagree. While this individual line of code may seem particularly offensive, it was written that way to be extremely clear and minimize dependencies. A more structured web app would be doing much more with the error depending on the situation. I'm glad that the code to handle those errors would be right around the logical point it should be: where I'm performing the action. Many of the handlers have some boiler plate error checking on some actions that could fail. I agree those lines of code are repetitive and aesthetically displeasing, but as I alluded to in the article, a more filled in app could define a handler type that returns an error instead of being expected it to handle it within. The http.Error calls would change to returns, but that's a good thing: a quick scan allows me to see when the function can return to the caller. I don't have to inspect every line of code and remember details about which calls throw exceptions or not. Nothing is hidden, and the code does exactly what it says on the page. Give me a slightly more verbose but clear code base than a terse one with spooky action at a distance any day.