The end error could then be something for example:
Error rendering template: Compiler has failed: Cannot load template: File /tmp/test.tpl was not found
------------------------ ------------------- -------------------- --------------------------------
| | | |
Returned by that | | |
example Returned by the | |
fictional compiler Returned by the |
fictional template Returned by the fictional file
Loader reader
I didn't even twist your example, and yet you can already see more information. And with that information, even a user can understand what's going on clearly. So ... more useful?
Oops, I forgot if errors.New takes the 'cause' as well.
Regarding you example: the code itself still contains redundant information for someone reading it. True, the error ends up being nicer, though I would argue that the user would have been better served with a simple 'failed to load template file: /tmp/test.tpl', no need to show the pseudo call stack (so, only the fictional template loader should have been wrapping the error,for this particular case). And for a developer, the full call stack may be more useful. Exceptions would give you both for free - a nice message that can be shared to the user by whoever caused the most understandable error, and a call stack that can be logged at the upper layer so developers can see it if a bug is logged, and get a much fuller context.
The full call stack is available in Go but it is up to the developer if they want to include it or not which they can do by creating a custom error type and implementing that to be part of their type. And having the choice seems like a benefit to me.
If above is true, then how about:
The end error could then be something for example: I didn't even twist your example, and yet you can already see more information. And with that information, even a user can understand what's going on clearly. So ... more useful?