Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Go has something that is functionally equivalent to exceptions; they just don't call them exceptions and make them look a lot different from what we are used to.


If you're talking about panics, you can only handle them in defer funcs if I'm not mistaken, which makes them significantly different from exceptions that I'm used to that can be caught in any part of the code. The dependency on defer in my opinion makes them unusable as typical exceptions in my case. This was perhaps the intent, making panics and the recoveries thereof truly exceptional and painful, pushing one towards the normal error handling semantics, which is what I dislike.


> If you're talking about panics, you can only handle them in defer funcs if I'm not mistaken,

That's true...but no different from "exceptions can only be caught in catch blocks".

> which makes them significantly different from exceptions that I'm used to that can be caught in any part of the code.

It doesn't make them any different from exceptions -- just as a catch block can be anywhere up the call chain, a deferred function can have been set anywhere up the chain.

Defer is basically "finally", except the position is different, and "recover" inside it lets it also do what "catch" does.


It's true that you can only handle them in defer funcs, but the defer func could be anywhere up the stack, not just the current function you're inside.

(I'm not sure if that was your understanding or not)

"The panic and recover functions behave similarly to exceptions and try/catch in some other languages in that a panic causes the program stack to begin unwinding and recover can stop it. Deferred functions are still executed as the stack unwinds. If recover is called inside such a deferred function, the stack stops unwinding and recover returns the value (as an interface{}) that was passed to panic."

https://code.google.com/p/go-wiki/wiki/PanicAndRecover


Yes and no, errors are just return values. They’re not special, they are conventional. So you get the whole type system to express errors – they’re just values. And you don’t have a different control flow.

It’s not without warts. You can bail with panic(), which is essentially a throw.

It’s tedious to handle errors, but that’s because actually handling errors is tedious.


"Actually handling errors" isn't tedious at all in Scala. Chain flatMap() across methods that use Try[A], handle the Failure[_] at the other end, and you're done.

I'm not joking when I say it really is that easy. Go makes it (and, really, many other things) very difficult for reasons that are at best murky.


So you call say 3 methods, and at the end you have a "file not found" error... which call resulted in that failure? I don't know Scala specifically, but from what I know of most languages that support this kind of chaining, you can't tell. And that's the problem. Did your initialization fail to find it's config file in step 1? Did you fail to find the target file you were going to transform in step 2? Was there some other failure in step 3? You can't tell, so you can't actually handle the error.

This is effectively like doing this in Java:

  try {
      DoX()
      DoY()
      DoZ()
  } catch( Exception ) {
      // The code has no idea what failed here.
  }
Whereas, the go code looks like this:

  if err := DoX(); err != nil {
      // handle error from DoX
  }
  if err := DoY(); err != nil {
      // handle error from Doy
  }
  if err := DoZ(); err != nil {
      // handle error from DoZ
  }
This is what Go programmers means when they say "actually handle the errors". At each step you handle the specific failure from the specific call. It's somewhat more verbose, but it's a LOT more robust against real life failures.


You'd have the same effect (you don't know what specific call failed) if all of the comment lines said "return err", which is a common pattern in Go. The Scala approach mentioned is just sugar for that. You can of course handle each case separately if you want in Scala, just as you can in Go, but the common pattern has sugar.


What? Actually, absolutely not.

If you only care about whether something succeeded use Option, if you care about the error use Either, Validation, etc.

Just pick the right Monad.


Yes, I agree, but I don't see how that's related to what I said.


Then maybe don't comment?


> So you call say 3 methods, and at the end you have a "file not found" error... which call resulted in that failure?

The first exception hit pops out the other side and you pattern-match against it. So, the one that did file access and returned a FileNotFoundException. If you have multiple pieces of code that can return FileNotFoundExceptions, you can pass a message in the exception, just like any other Java exception. You can often be more type-specific, too. Bear in mind that defining a new exception in Scala is a one-liner, and you can encapsulate your FileNotFoundException in a RetrievalFailedException very easily and cleanly.

Your method is not more robust, I assure you--it's just verbose and both typo- and thinko-prone.


Errors are just return value, but in go, you either explicitly ignore the error returned (using the "blank identifier" _ ), or, you assign it, in which case you have to deal with it (otherwise go will complain about an unused variable).

An that is what makes go awesome. In java or php, you, as a developer, can never know wether the functions you are calling will throw an exception. The only way to know? Read the doc, if you're lucky and there's a doc, or read the code... The result? your program will crash if you didn't add your try..catch block.

Go forces you to either explicitly ignore errors (and your fellow co-worker will know you did it on purpose) or deal with them. No surprises.


I get the same in C, with gcc's __attribute__((warn_unused_result)).


This comment should be more prominent, warn_unused_result is pretty awesome!


> In java or php, you, as a developer, can never know wether the functions you are calling will throw an exception.

That's what checked exceptions are for in Java.


The larger problem with exceptions, checked or not, is that they interrupt the flow of your program, which is too bad since most exceptions are not that exceptional. That problem is exacerbated by developers who don't know how and when to throw exceptions and end up throwing exceptions for easily recoverable errors. The other thing I dislike about exception is that your code ends up with tons of try..catch blocks.


It's that convention and exclusion of special abstractions that appeals to me by keeping the cognitive load to a minimum. I can focus on the problem without thinking about the language. If Go became like various other languages, then what would be the point? We already have Java, C#, ...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: