Standard, accepted practice for Exception handling.

Exceptional Programming

You’re exceptional. Shouldn’t your code be, too?

This article is exclusive to Pointer — a reading club for developers.
Sign up at Pointer.io for our weekly newsletter.

Exceptions have been a first-class citizen in many programming languages for years. Where once we might have ignored them, thinking that they were just for programmers that actually made mistakes in their code, we now cannot avoid them.

Even calling some methods requires that we handle exceptions that they might throw which, honestly, seems a little awkward. It’s like the authors of that code are saying, “Here’s this thing we wrote, but it’s not perfect. In fact, it might break. Actually, it probably will. But lucky for you, we’ll tell you about it when it does. Then it’s on you.” It’s like when a glass develops a small crack on the rim — you could probably have gotten by without knowing about it, except for the cut it leaves on your lip and and the accompanying blood trail of evidence.

But still, our tendency may be to just catch the exception and move on because, again, we don’t actually make mistakes in our code. Bugs are things that other developers write. Right? So we wind up with code like this:

try {
someMethod();
} catch (Exception e) {
// Totally won't happen, like, ever
}

Or we could keep pushing the problem down the code road. After all, it’s not our code that failed, but the code that we called. So we might do this instead:

public method MyFlawlessMethod throws SomebodyElsesException() {
try {
// ...
} catch (Exception e) {
throw new SomebodyElsesException("This wasn't my fault", e);
}
}

But even this reasonable approach seems somehow lacking. I mean, it’s laying the blame correctly and appropriately. And it’s even propagating the error in a potentially useful way (especially because it’s making it clear that it’s somebody else’s fault, and not ours. Because our code would never fail. Ever.). But it’s still missing something — it’s missing an opportunity for a better workflow.

In programming, we’re always searching for patterns, workflows, processes, ideas, algorithms — behaviors that we can incorporate into our jobs to improve our productivity and, even more, reduce the inherent boredom of our lives by trying something new. Also, new things allow us to broaden our experiences by going to developer conferences to learn about these new things, where we’ll probably get free beer and t-shirts. And they enable new items in our performance reviews, where self-education can often shine in comparison to actual output. And for the business-minded among us, they enable new skills which we can then teach others and build training consultancies around.

So let’s take another look at Exceptions in this new light — the light of something shiny and new. In particular, allow me to introduce an entirely new style of programming: Exceptional Programming.

Exceptional Programming is the art and science of using Exceptions — and only Exceptions — as the control flow mechanism for code.

Control flow has lingered in the same festering bit swamp since forever. Originally, code would move linearly from start to end:

10 PRINT "FART"
20 END

Then exciting, new languages like FORTRAN and BASIC added branching statements, which allowed interesting possibilities layered on top of the traditional linear flow:

10 PRINT "FART"
20 GOTO 10
30 END

Similarly, COBOL handled the concept of GOTO in it’s more explanatory fashion:

00410 PROCEDURE DIVISION.
00420
00430 GO TO THE PLACE IN THE CODE THAT FOLLOWS THIS LINE OF CODE, ENTITLED "NEXT LINE OF CODE".
00440 NEXT LINE OF CODE: THIS IS THE NEXT LINE OF CODE
00450 OUTPUT TO THE TERMINAL WINDOW THE PHRASE, "FLATULENCE"
00460 GO TO THE PLACE IN THE CODE THAT PRECEDES THIS LINE OF CODE THAT WE ARE CURRENTLY ON, WHICH IS NUMBERED 00460, WHEREAS THE PREVIOUS LINE OF CODE IS NUMBERED 00450, COMING AS IT DOES BEFORE 00460 BUT AFTER THE PREVIOUS LINE OF CODE 00440, WHERE LINES ARE INCREMENTED BY 10

The introduction of loops and conditions enhanced this capability with more flexible control of branching:

10 DIM I AS INTEGER
20 FOR I = 0 TO 100
30 IF (I % 10) != 0
40 PRINT "FART"
50 ELSE
60 PRINT "HA!"
70 NEXT I
80 PRINT "HA, HA, HA, HA!"
90 END

Then, finally, the introduction of functions in languages allowed GOTO-like branching with the added benefit of being able to pretend that you don’t use GOTO. At the same time, these language inventors discovered lower-case letters.

public static void main(String args) {
new MyThing().someMethod();
}
private void someMethod() {
for (int i = 0; i < 100; ++i) {
resultPrinter(i);
}
System.out.println("HA, HA, HA, HA!"
}
private void resultPrinter(int i) {
System.out.println((i % 10 != 0) ? "FART!" : "HA!");
}

Today, developers have a myriad of ways to alter the control flow. But code still proceeds linearly — if you’re not GOTO’ing, calling a function, or looping, you’re always moving forward. But moving in a straight line is an artificial construct. If people were meant to always move in a straight line, we would have no need for roadside sobriety tests, or guard rails on straight bridges. So why should our code be any more constrained than we are?

Introducing Exceptional Programming, where the code flows only where the exceptions tell it to. There is no forward, there is no back — each statement exists on its own, in its own universe, beholden to nothing except exceptions.

The details must wait for the final release of this important new construct, but some simple examples will show why this is so important.

First, the basics. Here we see how we key off of Exceptions to control the flow on every single statement. This allows us to fine-tune exactly when and where problems occur, because every statement is exception-friendly (what we call Exceptional). But also, this approach allows us to control the execution of every line of code, because the exceptions direct how and where the code will flow. Exceptions are the line numbers of this new paradigm, sign posts guiding us in where to go and telling us where we are.

public void main(String args) throws Exception {
try {
someMethod();
} catch (NormalException e) {
try {
anotherMethod();
} catch (NormalException e) {
try {
yetAnotherMethod();
} catch (NormalException e) {
throw new NormalException("Everything's fine");
}
}
} finally {
throw new NormalException("Everything's fine");
}
}
Exceptions are the new line numbers.

Of course, one of the reasons that we’ve all avoided handling Exceptions in the past is that it’s just too verbose. As Hamlet famously said of his Java Exception-handling experience:

Words, words, words.

Fortunately, we’ve dealt with this issue in Exceptional Programming, and the previous example can be shortened to the following:

public void main(String args) throws Exception 
throw new NormalException(
throw new NormalException(
throw new NormalException("Everything's Fine", () ->
someMethod();
);
anotherMethod();
);
yetAnotherMethod();
);
}

Fans of The Annotated Programmer will be happy to learn that Exceptional Programming will incorporate annotations to make things even more concise and usable. With optional annotations, the above example can be written simply as:

@NormalException("Everything's Fine")
public void main(String args) {
someMethod();
anotherMethod();
yetAnotherMethod();
}

Critics of this exciting new approach point out that the above is basically what we had before, but that we’re using annotations to ignore exceptions for us.

But I take Exception to that.

In software development, mistakes are the exception.
Exceptions are the cure.