You surely know that it is very common to rethrow the original exception wrapped in languages with try-catch — it still saves you the time to write that (plus it is safe, no code, plus stacktrace). It is still strictly better than whatever go has.
I've written a lot of try/catch but no one in those languages do that for every branch, it's usually just everything wrapped in a big try/catch.
Go makes you deal with the error every single time something could go wrong, so you have a chance to do the right thing and append context at every single failure path.
Go makes you believe you dealt with the error, but instead you just forget about it.
Also, checked exceptions are very much not like that, and being able to handle errors of a logical unit is also beneficiary (e.g. transactions). You are free to use the scope-size that makes sense for the given use case.
> Go makes you believe you dealt with the error, but instead you just forget about it.
Can you explain that? Touching every context of an error propagation seems opposite of forgetting about it.
haha, so true. I almost always wrap errors at every level with addition context. If it was worth doing, then it's worth explaining.
People that prefer try/catching large sections of functionality or want to skip verbose handling of errors often have not thought through the user or tester experience. Heck, even trying to recreate the issue/state from production.
if err != nil { return err }
vs
if err != nil { return fmt.Errorf("context here: %s: %w", action_type, err) } (or wrapping some custom app error with context for the trace)
Of course you don't want to leak private details, but often there is a public component that is worth adding. This also brings up the concept of dual-error chains where what you log and what you report to the client are different.