Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

“We had thought… that exceptions would be a way to handle errors. We were wrong. They are a way to handle the inability to handle errors.” — paraphrased, with no apologies, from twenty-five years of C++ committee discussion

This is a book about a problem that the working software industry has, on the whole, decided not to think about.

The problem is small to state. When control flow leaves a function in a way that the function did not write code to handle, what is the state of the world? Are the invariants the function maintained still true? Are the resources the function acquired released? If a partial change was applied to a data structure, has it been undone, or has it been left half-applied for the next caller to discover the hard way?

The answers — for the code you ship, today, in production — are usually one of:

  1. I have never asked.
  2. I asked once and the answer was unsatisfying so I stopped asking.
  3. I’m pretty sure RAII or defer or with handles it.

None of these is wrong, exactly. They are just not enough. The discipline of exception safety is the discipline of asking these questions on purpose, with vocabulary precise enough to actually answer them, and then writing code that gives an answer you can defend in front of someone who knows what to look for.

Who this book is for

You know what try and catch are. You probably know what finally is. You may have written a destructor, or a defer statement, or a with block, or a using clause. You have heard the words “exception safe” and you have a hunch they mean something more than “doesn’t crash.”

You are, in other words, every working engineer.

This book is not a tutorial. It is closer in spirit to Exceptional C++ by Herb Sutter and Modern C++ Design by Andrei Alexandrescu — books that took the problem seriously and assumed you’d already met the basics. The difference is scope: those books were about C++. This one is about every language you might ship in, and every place outside of try/catch where the same shape of problem keeps showing up wearing a different hat.

What this book is not

It is not a defense of exceptions, and it is not an attack on them. The Go community has, more or less, decided exceptions are a mistake; the C++ community has, more or less, decided they are tolerable if handled with care; the Rust community has, more or less, decided that the unwinding mechanism should exist but be used as a last resort and ideally not in library code at all. These are reasonable, mutually contradictory positions held by intelligent people, and you will not find this book trying to settle the argument. You will find it pointing out that the underlying problem doesn’t go away just because you removed the keyword. If you panic in Go, or return an Err(_) from a Rust function that was halfway through a multi-step state mutation, or your iMessage handler gets an EINTR mid-write, you have an exception-safety problem with a different name.

How this book is organized

Part I (chapters 1–4) does the foundational work: what exceptions actually are at the machine level, the formal vocabulary of the three guarantees, RAII as the canonical defense and its limits, and the small set of patterns that buy you the strong guarantee when you need it.

Part II (chapters 5–6) is the cross-language tour. C++, Java, Python, C#, Rust, Go, and JavaScript get one chapter; Common Lisp gets its own, because the condition system is, frankly, a different category of object than what those other languages call exception handling, and pretending otherwise would be dishonest.

Part III (chapters 7–9) is where the book earns its keep. Concurrent code. The DAO. Signal handlers. Saga compensations. Each one is the same problem dressed differently, and the failure modes are the same failure modes, and the fix patterns are the same fix patterns, and once you see the shape you cannot unsee it.

Part IV (chapters 10–12) is what to do about it. Tooling, real bug post-mortems, and a short list of disciplines that get you most of the way without rewriting your codebase.

A note on tone

I am going to be direct about how badly the industry has failed to grapple with this. That is not an aesthetic choice; it is the only honest framing of the situation. We collectively ship enormous amounts of code that handles errors in ways that nobody has thought through carefully, and it bites us — not theoretically, but in production, in money, in human time, and occasionally, in dollars on a blockchain that someone took because we didn’t reorder three lines.

I will, at points, admit that I do not fully grok parts of this. You should not fully grok them either after the first read. The problem is genuinely subtle. If after this book you can argue precisely about which guarantee a function provides and what would have to change about the function to upgrade it, you have already made yourself more dangerous than 95% of the engineers the field has produced. That is the goal.

Let’s begin.