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

Every time I switch back to exception languages, I get this tendency to "assume everything succeeds all the time, and handle it at the very top level in case any part of it fails". I do not think about what can go wrong at each level nearly as much as I do when I am required to use `if err != nil` soup.



> Every time I switch back to exception languages, I get this tendency to "assume everything succeeds all the time, and handle it at the very top level in case any part of it fails"

See, I get the exact opposite tendency. Exceptions mean that any statement, no matter how seemingly trivial from the caller's perspective, can fail. It means I'm constantly thinking "If an exception is thrown between X() and Y(), does it break any assumptions I've made about the program state?". You end up with hacks like putting code in finally blocks just to prevent partial execution.

I think exceptions would work fine in a language that also had built-in support for transactional memory, where you could commit or rollback operations when an exception is thrown partway through. Without any language support, though, I think that exceptions and mutable state do not play nicely with one another.


> Every time I switch back to exception languages, I get this tendency to "assume everything succeeds all the time, and handle it at the very top level in case any part of it fails". I do not think about what can go wrong at each level nearly as much as I do when I am required to use `if err != nil` soup.

This is generally the best way to deal with errors. In most cases, only the original caller really knows which errors ought to be considered fatal, and which should result in retries or be handled in some other way.

If you handle errors deep down in the call stack, you are robbing the caller of the ability to decide how to handle them. Different callers may want different things. It is better to let errors bubble up as far as possible.


Exactly. And in most cases I don't care. Can't open that file? That's a fatal error. Can't connect to the DB? That's a fatal error. Some file system operation failed? That's a fatal error.

In the majority of applications it's normally pretty obvious which errors you're likely to care about (the user already exists, etc.) vs the rest that you just handle at the top level. The trouble with go's error handling is it makes you care about everything, which is just a waste of time and effort because the majority of errors will be fatal anyway.


I completely agree. I love that go is _able_ to treat errors just like return values but most of the time I don't need to work with them like that. I want to assume the happy path and not have all the `if err != nil` noise.


Coming from Java I agree: that's what tends to happen, but I miss it when I don't have it.

It's helpful habit for services especially because most of what you're doing is local to a request anyway and you want to "undo" or "drop" things. Exceptions in services are great because they actually preserve situational information pretty well and a catch+rethrow is pretty good for annotations at different levels. Err/panic are so poor at capturing anything of value by default. They require a ton of diligence to be useful.

The nice thing about being able to catch exceptions is that I can kinda define what operations are "atomic" on my terms.

Presumptuous example disclaimer.

For instance, if I'm processing a set of files with records, I'll probably have a substantial error domain around the processing of a record, of a whole file, and my whole program. I don't want to babysit each byte read.

Now, I admit, this does require you to write code that didn't pollute your state with partial work. Unwinding from a frame/function should leave everything in a known place.


Yes, I like that part of exceptions. I can hold more of the problem in my mind when I don’t need to worry about what happens when something exceptional happens.


>I get this tendency to "assume everything succeeds all the time, and handle it at the very top level in case any part of it fails"

Which is not bad at all.

In fact, it's closer to how e.g. Erlang works.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: