It's even easier to not use exceptions either and let your supervision tree, process monitor, hardware heartbeat switch and/or night operator handle it.
This is the right answer really. In large at least that's how sane operating systems deal with failed components (processes). They crash, but then they can restart if monitored by a supervisor (systemd / init). On a higher level most places handle it as well at machine / node level -- auto-failover, auto-provision, health-monitoring, centralized logging. All that is the right answer to building concurrent systems, except most current languages except a few (Erlang / Elixir) are stuck in the equivalent of early 90's Microsoft Windows 3.1 environment.
It's easier to use exceptions and not care about the origin of an error when the details are irrelevant.
Exactly -- I get annoyed by having to write 20 `if err != nil {`s when just one `catch` in another language would work. IMO, this is one instance of Go's maintainers conflating language simplicity with compiler simplicity.
> IMO, this is one instance of Go's maintainers conflating language simplicity with compiler simplicity.
Lol, I thought a long time about how I could express that feeling. now I understand, in Go the developer is doing the compiler's work ...
Perhaps the sentiment is valid, but practically speaking, in Rust you do even more of the compiler's work for it, no? I suppose one could just cherry-pick an analogue of the `try!` macro into Go.
Agreed, Rust's way of error handling with Result and try! (or ?) is far superior.
Monads are not that hard either :) Once you get used to Maybe/Option and Either, you don't want to look back to error codes or exceptions.
Easier to use exceptions and allow RAII to clean up resources automatically, making all error paths work smoothly.