My philosophy of exceptions: they’re always ambiguous
Python, C++, Ruby and Java all use exceptions. To them, “exception” means, “nifty piece of syntax kinda like goto
.” Language specifications and communities haven’t defined “exception” in a way humans can understand.
It’s the only incomprehensible term out there. Anybody who’s programmed for five hours can explain “if” to a human. Same goes for “else”, “while” and “for”. Deeper concepts like “function” and “class” can be clarified, too. Humans can even grasp flawed terms — like, “int” meaning “32-bit signed integer” and not “integer”.
But “exception” is completely incomprehensible. Ask ten beginners and ten experts to define “exception” to a human non-programmer, and you’ll hear 20 vastly different answers.
All those answers will be wrong.
Exceptions are the norm, not the exception
So you think you know what an “exception” means? Let’s look into a Python example:
# How many exceptions can this code raise?
url = input("Please enter a URL: ") # wait for user input
with urllib.request.urlopen(url) as response: # request the url
bytes = response.read()
text = bytes.decode("utf-8")
print(text) # print the HTML
Here’s the big lie: in Python, this snippet will almost always raise an Exception.
That’s because most users, faced with an input prompt, will press Ctrl+C or enter a non-URL. And even if they enter a URL, it probably has a typo. And even if it’s right, Internet connections and web servers are flaky —when they’re there at all.
In English, “exception” means, “something unusual.” But if this code snipet raises ValueError
60 per cent of the time and prints the contents of a web page 10 per cent of the time … well, surely we need a new term?
Do we even need a definition?
Obviously, programmers have been reasoning about exceptions for decades without defining what “exception” means. There’s clear evidence: all these programs written in C++, Python, Java and Ruby.
But every language, every library, every codebase — heck, every individual developer — has an opinion on what is exceptional and what is normal. And so every language, every library, every codebase and every developer writes and teaches different code. API conversations become philosophical debates.
When you see clever programmers debating the meaning of “exception”, that’s a team at war with its programming language. There’s no right answer.
What’s better?
Sorry — this is how it is. Learn to live with it.
In Scala or Rust, you’ll write “matchers” to deal with all possible outcomes of an expression. Matchers make it easier to write correct code, because the compiler will nudge you if you forget an error.
If you’re using Python, you’re stuck with the endless debates. For instance, you’ll never know why there’s a dict.get()
to avoid KeyError
but no list.get()
to avoid IndexError
.
When I shifted from Rust to Python, I tried to write matcher-style code. It wasn’t legible. I became irate.
A better approach is to meditate — and document every function you write. Describe each possible exception and all the cases that can lead to it. Look to Javadocs as a good example.
But don’t expect anybody to agree with your philosophy.