Exception handling in various languages
Recently I have been doing quite a lot of thinking about error handling in various languages -- in particular exception handling. There are two major languages where I do have a bit of experience with writing large code bases -- python and java. And they take widely varying approaches to handling exceptions.
While Java has typed exceptions, and compile time checking of the typed exceptions python has unchecked exceptions. I have been thinking of the pros and cons of these, and here are my thoughts:
Checked exceptions are the bees knees when used properly. "Used properly" is the most important bit here. Checked exceptions should be thrown only for errors that are expected. Like when validation fails on user input, or a file that's supposed to exist goes for a walk through the forest of corruption. Unchecked exceptions should never ever by thrown by the code itself.
Checked exceptions are great because it serves as a great documentation of the possible erros that can happen for the given code. Of course, it's not possible for an average programmer to foresee all possible edge cases. And not all programmers are diligent enough to try.
Checked exceptions are great for use in libraries, to signal possible programming errors and bugs in the code that uses the library. For certain classes of software, it makes even more sense, if it provides a safe way to retry.
For example, writing to a database, or doing a write operation on any service. Having an idempotency key or some such to safely retry the given operation is invaluable.
The existence of unchecked exceptions, on the other hand, is completely incomprehensible and baffling. Let me be more specific here -- allowing a programmer to throw an unchecked exception in a compiled language is completely incomprehensible and baffling. The only source of untyped exceptions should be the runtime environment itself.
But in the case of interpreted languages like python, checked exceptions aren't really an option. Libraries throw arbitrary exceptions, and with bad documentation, it makes it almost impossible to write code that doesn't crash every now and then, until, by trial and error, or perusing the source code, you've figured out all the possible exceptions the library throws, and handle them appropriately. Really, that's really bad user experience. Well to be fair, having bad documentation was the real root cause here.
Enter go. It's design of exception handling is one of the most promising yet. Returning error codes with the return value, and putting the onus on the programmer to check the return value and the error code before using it can lead to pretty good code.
Take for example of a http library. If the call fails, as it inevitably will at some point, networks being what they are, you can just get back an empty return value, and the error code. Worst case when it fails for an unexpected reason, you still get back an empty return value, and a misleading error code. Seeing as it is a http library, it's not the end of the world if the call fails. An empty return value isn't going to cause that much damage since you probably already have code to handle it. Getting an unexpected exception on the other hand, that's going to crash your program, and lead to all sorts of headaches.
I mean, really, how much do you care why you get an empty result, as long as you can be sure it wasn't a bug in your program? Of all the errors you can get on a http call, only a handful are really client errors. Rest are errors you can't do anything about but retry.
Anyways, the point is that before you throw an exception, make sure you really need to throw that exception there. The other point is that, Google Go looks awesome.
Comments powered by Talkyard.