Hacker News new | past | comments | ask | show | jobs | submit login

It's just exception throw/catch. The only difference to other languages is that you're not supposed to use it, as a matter of principle.



They're not meant to be used like that (and terminate the function, not the block), so the implementation can have more overhead than try/catch. What bothers me about it is that there's no syntax for it: recover as it is looks like a dirty hack.

I've been writing my first production software in go this year, and I must say I'm quite favorable towards its error handling now, ugly as it may look. Even during testing there haven't been any crashes except in the places where you can expect them (like writing x := y.(string) when y isn't a string).

For me, the only real downside in go: nil pointers in combination with the absence of non-nullable types.


This is my experience after 7 years of Go as well. Error handling is actually fine. People make too big a deal about the error check (and Rust people make too big a deal about the compiler not forcing you to handle every error). The substantial opportunities to improve error handling involve establishing a standard, typesafe interface for getting at the relevant, structured information in an error so callers can handle things properly; however this probably depends on generics and sum types and will probably look a lot like Rust’s result types (which seems great to me). In practice these are not where your bugs are. On the other hand, sum types would actually go a long way in reducing bugs (including the nil pointer problems you mention).


You're not supposed to use struct tags, type aliases, "interface {}" or reflection either... that's a lot of features Go developers "aren't supposed to use"... Why are they here then?


Frequent use of these patterns is a good smell test that one should reconsider design choices. Are there times when usage is justified? Yes. Should it be the first / default mechanism? No. Learn the rules first, and then it will be more clear when you should break them.

I have no problem with the general rule nor a built-in mechanism for breaking them.

Simple example: if I ever have a row lock I wrap the corresponding block in recover to ensure that I never have a deadlock. But I certainly don’t wrap every function in recover...


These features do not scale so one should take care to use these language features only when necessary. Also the OP is not Gospel of Go, merely an expressed opinion.


There's no problem with using any of those features; they just come with some drawbacks and in many cases they're not the best tool. But in some cases they are, and then by all means go ahead and use them. They exist for a reason.


It's not really, because there is no straightforward way to express something like:

  def f():
    bar()

    try:
      foo()
    catch KeyError as exc:
      print(exc)
Calling recover() in a defer applies to the entire function, so you'll need to wrap foo() in an anonymous function. You also need more work to not use "Pokemon exceptions" (gotta catch 'em all) and recover() only KeyError


The only time I have used recover in production code is in the rollback path of a highly concurrent transaction manager.


try/throw/catch work at block-level. panic/recover are not an option until function-level


Rather, it should (not must) be used for exceptional cases, like if something happens and you have no idea how to deal with it.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: