2 ms·
Go's rejection of exceptions comes from the philosophical ground that errors should be expected no matter how unlikely they are, and the programmer must make a
by xiaq 9y ago
Go's rejection of exceptions comes from the philosophical ground that errors should be expected no matter how unlikely they are, and the programmer must make a conscious effort to think about how to handle errors - either by attempting to recover from it (probably with some logging) or passing it to the caller (after annotating and possibly reclassifying the error). Pike argues that different applications require different strategies, and there is no single solution that fits all. No strategy is biased by the language; the choice must be made consciously. Hence no auto propagation of exceptions.
Exceptions optimize for the use case of passing it to the caller because that is indeed more common, especially when writing libraries. However, it makes recovering unnecessarily verbose. In the worst case, you may need to nest the call to every exception-throwing function in a try block. Exceptions also carry the danger of spoiling the developer: it encourages developers to think less about errors because they are "exceptions". When errors do happen, the exception being thrown often carries little information about what is really wrong.
This problem is mitigated by stack traces, but stack traces do not always have the entire context. If an AccessDeniedException is thrown during a multi-step operation, do we know which user is denied access and which step denies access? A carefully designed library will populate the exception with user information when throwing it, and likely catch and rethrow it to add more information. Does this sound familiar? This is exactly what Pike is advocating in this article. It requires you to think about the execution flow of your program not in terms of function calls, but in terms of more high-level operation steps that the user can also understand to some extent.
At the end of the day, even in a language with exceptions, error handling code can still benefit from the approach Pike advocates. If executed well, it makes the stack trace unnecessary, because the "operation traces" should now contain enough information.
However, this approach requires a lot of discipline, and the programmer must have a clear picture of all logical operations involved. Unfortunately that is not always possible; programs can easily become too large for one person to completely grasp how it operates in a limited amount of time.
To conclude, in the perfect world where programmers always have a clear understanding of all the operation steps involved in a program, Pike's approach is flawless. But in the world we live in where no one ever knows entirely what is going on, automatic stack traces are (still) a sensible fallback. Yet, I take this as a protest against the status quo rather than an oversight: programs should not grow too large for a programmer to grok, and programmers should strive continuously to simplify and understand the programs they maintain.
- sagichmal 9y agoWhat an excellent comment. Thank you for writing it.