Questions About Exception Specifications

In the past few days, I’ve had several people independently send me email to ask related questions about exception specifications. That must be reason enough to echo some answers here.

Background

For background, here are two places where I’ve written about exception specifications:

I’ve taken the liberty of pasting the entire latter reference at the bottom of this post. Enjoy!

Now on to Question the First…

Q1: How can you know you’ve caught everything if you don’t use exception specifications?

Andrew Skypeck asked:

In CCS#75 you suggest that one ought not provide an exception specifications with functions. Without them, how can a user of the function be certain they have caught all possible exceptions without inspecting the code they are calling? This is often not possible for API users that have header files only.

Two thoughts:

First, the way to catch everything is to catch(…), and that always works. You seem to be wanting to use exception specifications as documentation (which is fine), and so you can get the same ability by writing the exception specification as a comment. Note that even if you try to write them all as actual code, you can’t do it in general — notably you can’t do it for templates, because if a template can be instantiated with any type, you generally can’t know in advance what it might throw.

Second, the caller of a function doesn’t always need to catch all possible exceptions; it should only catch the exceptions that it knows how to handle (or translate). Exception safety is not just about making sure that the code that knows how to detect an error throws, and that the code that knows how to handle the error catches; rather, in practice exception safety is largely about making sure the code in between stays out of the way, including that it doesn’t catch and absorb exceptions. For more about this aspect of exception safety, start with these Items in C++ Coding Standards, and follow the references at the end of each Item to dig into the details that interest you:

  • 70. Distinguish between errors and non-errors.
  • 71. Design and write error-safe code.
  • 72. Prefer to use exceptions to report errors.
  • 74. Report, handle, and translate errors appropriately.

Which brings us to Question the Second:

Q2: Why not statically enforce exception specifications?

Bob Rossi asked, while kindly citing the above article:

I would like to know what the possibilities are of C++0x enforcing the exception specifications like Java does. Here is a good article describing why exception specifications acting the way they do are currently bad, http://www.gotw.ca/publications/mill22.htm

I must not fully understand the situation. What is wrong with the compiler time checks that Java does to enforce the exception specifications? I find this feature extremely useful as a developer!

The short answer is that nobody knows how to fix exception specifications in any language, because the dynamic enforcement C++ chose has only different (not greater or fewer) problems than the static enforcement Java chose.

If you’re interested in reading more about this, try googling for newsgroup postings, http://groups.google.com/groups?q=sutter+exception+specifications. The following is taken from the second hit, which I wrote last fall:

Essentially, exception specifications are a wonderful idea in basic principle, but no one really knows how to design them.

There are two major approaches, and both have serious problems. Java chose static enforcement (at compile time, as suggested above), and C++ chose dynamic enforcement. Interestingly, I see Java people ask "why not enforce these dynamically?" about as often as I see C++ people ask "why not enforce these statically?"

Briefly:

When you go down the Java path, people love exception specifications until they find themselves all too often encouraged, or even forced, to add throws Exception, which immediately renders the exception specification entirely meaningless. (Example: Imagine writing a Java generic that manipulates an arbitrary type T…)

When you go down the C++ path, people love exception specifications until they discover that violating one means invoking terminate, which is almost never what you want.

So why did C++ do exception specifications the way it did, with dynamic enforcement via terminate? And why did Java do it the other way? In both cases, it seemed like a good idea that avoided some set of known problems, and you can’t always know the new problems you incur instead until you gain experience with multiple releases of large code bases, which means over time.

The future of exception specifications?

Bob responded by asking why we don’t just fix exception specifications, or remove them entirely until something better comes along. Those are good questions.

Taking the latter part first: As tempting as it may be, one can’t just rip out a language feature because one decides it isn’t working out quite right. The primary reason is that there are people using the feature, and breaking existing legal code is, well, rude.

What about fixing exception specifications? That would be nice, and I think nearly everyone I know is willing to consider changing them, but only if: (a) there is a well-understood replacement (there isn’t today), and (b) there was a good way to deal with migration from existing code which may rely on the existing feature.

Deliberate change with a strong dose of backward compatibility is always the key. This one needs more deliberation, at least for now, and isn’t expected to change in C++0x.

Epilogue: C++CS Item 75

I’m sure Addison-Wesley won’t mind overmuch if I paste one Item here in its entirety. It has been slightly reformatted for the web.

75. Avoid exception specifications.

Summary

Take exception to these specifications: Don’t write exception specifications on your functions unless you’re forced to (because other code you can’t change has already introduced them; see Exceptions).

Discussion

In brief, don’t bother with exception specifications. Even experts don’t bother. The main problems with exception specifications are that they’re only “sort of” part of the type system, they don’t do what most people think, and you almost always don’t want what they actually do.

Exception specifications aren’t part of a function’s type, except when they are. They form a shadow type system whereby writing an exception specification is variously:

  • Illegal: In a typedef for a pointer to function.
  • Allowed: In the identical code without the typedef.
  • Required: In the declaration of a virtual function that overrides a base class virtual function that has an exception specification.
  • Implicit and automatic: In the declaration of the constructors, assignment operators, and destructors when they are implicitly generated by the compiler.

A common but nevertheless incorrect belief is that exception specifications statically guarantee that functions will throw only listed exceptions (possibly none), and enable compiler optimizations based on that knowledge.

In fact, exception specifications actually do something slightly but fundamentally different: They cause the compiler to inject additional run-time overhead in the form of implicit try/catch blocks around the function body to enforce via run-time checking that the function does in fact emit only listed exceptions (possibly none), unless the compiler can statically prove that the exception specification can never be violated in which case it is free to optimize the checking away. And exception specifications can both enable and prevent further compiler optimizations (besides the inherent overhead already described); for example, some compilers refuse to inline functions that have exception specifications.

Worst of all, however, is that exception specifications are a blunt instrument: When violated, by default they immediately terminate your program. You can register an unexpected_handler, but it’s highly unlikely to help you much because you get exactly one global handler and the only way the handler could avoid immediately calling terminate would be to rethrow an exception that is permissible—but because you have only one handler for your whole application, it’s hard to see how it could do useful recovery or usefully know what exceptions might be legal without trivializing exception specifications altogether (e.g., following the discipline of having all exception specifications allow some general UnknownException eliminates any advantage that having an exception specification might have had in the first place).

You generally can’t write useful exception specifications for function templates anyway, because you generally can’t tell what exceptions the types they operate on might throw.

Paying a performance overhead in exchange for enforcements that are nearly always useless because they are fatal if they ever fire is an excellent example of a premature pessimization (see Item 9).

These is no easy fix for the problems described in this Item. In particular, the problems are not easily solved by switching to static checking. People often suggest switching from dynamically checked exception specifications to statically checked ones, as provided in Java and other languages. In short, that just trades one set of problems for another; users of languages with statically checked exception specifications seem to equally often suggest switching to dynamically checked ones.

Exceptions

If you have to override a base class virtual function that already has an exception spec­ifi­ca­tion (e.g., ahem, std::exception::what), and you don’t have the ability to change the class to remove the exception specifications (or to convince the class’s main­tainer to remove them), you will have to write a compatible exception specification on your overriding function, and you should prefer to make it no less restrictive than the base version so as to minimize the frequency with which it might be violated:

// in a class written by someone else,
// the author used an exception specification,
// and if you can’t get him to remove it…

class Base { // …
virtual f() throw( X, Y, Z );
};

// … then in your own class your override
// must have a compatible (and preferably
// the identical) exception specification
class MyDerived : public Base { // …
  virtual f() throw( X, Y, Z );
};

[BoostLRG]’s experience is that a throws-nothing exception specification (i.e., throw()) on a non-inline function “may have some benefit with some compilers.” Not a stunning endorsement from one of the most highly regarded and expertly designed C++ library projects in the world.

References [see the C++CS online bibliography for reference details and other links]

[BoostLRG] – [Stroustrup00] §14.1, §14.6 – [Sutter04] §13

“Why Are You Doing What You’re Doing?”

For nearly a decade, I’ve had a plaque bearing that question on my desk.

I think the question is valuable because it goes directly to motive. It’s also a deliciously contextual question — it means something different every minute, depending on what you’re up to. Here are a few scattered examples:

  • "Why am I doing this job?" Is it because someone, or society, told me that this was "success" (see last week’s Friday Thought)? Because it’s a way to make ends meet? Because I really enjoy it? Because this is a fun and cohesive team? Because I’m too tired to look for another job? Because I don’t think I could make it at a job I’d actually like to do?
  • "Why am I writing the code this way?" Is it because someone told me to, even though I don’t completely understand the reason? Because it’s the right way? Because I’m under time pressure and plan to fix it later? Because it’s a short cut and I don’t care about this product? Because I haven’t looked in Knuth’s classic The Art of Computer Programming to see if there’s already a known better structure or algorithm? Because I’m tired or distracted? Or because of something else?
  • "Why did I fail to show appreciation for a friend’s help?" Is it because I failed to realize how much they helped me, and at what cost to themselves? Because I was too absorbed/tired/stressed/distracted with just my own troubles? Because I care, but repeatedly failed to show it when it mattered? Because perhaps I actually do need to care more about other people and actively take an interest in them? Because of some combination of the above, and/or possibly more reasons?
  • "Why am I driving to the store?" Is it because that’s what everyone does? Because it’s what I’ve always done? Because I don’t have time to walk or bike (and if so, why not)? Because the groceries are too heavy/bulky to carry back? Because I haven’t thought of riding a bike in years?
  • Etc.

Nobody’s perfect. I’ve wrestled with these and other questions, as I’m sure you do too, and try to improve a little every day and every year.

Being intentional is more than just about programming. We can get there if we keep trying.

Channel 9 Interview: Software Composability and the Future of Languages

Last week, Anders Hejlsberg, Erik Meijer, Brian Beckman and I recorded an interview/chat that covered a range of topics related to programming and languages.

The video is now available online. Here’s the summary pasted from the Channel 9 site:

Software Composability and the Future of Languages
Anders Hejlsberg, Herb Sutter, Erik Meijer, Brian Beckman

How will imperative programming languages evolve to suit the needs of developers in the age of Concurrency and Composability? What role can programming languages play in enabling true composability? What are the implications of LINQ on the future of managed (CLS-based) and unmanaged(C++) languages? How will our imperative languages (static) become more functional (dynamic) in nature while preserving their static "experience" for developers?

Answers to these questions and much more are to be found in this interview with some of Microsoft’s leading language designers and programming thought leaders: Anders Hejlsberg, Technical Fellow and Chief Architect of C#, Herb Sutter, Architect in the C++ language design group, Erik Meijer, Architect in both VB.Net and C# language design and programming language guru, and Brian Beckman, physicist and programming language architect working on VB.Net.

This is a great conversation with some of the industry’s most influential programming language designers. Tune in. You may be surprised by what you learn…

Apologies in advance if the video doesn’t work for some combination of platforms and browsers.

Ichiro on Success

What does the word "success" mean to you? There’s no shortage of opinions about what Success should mean and upon which particular Altar of Success we ought to sacrifice our lives and energies. That doesn’t mean those opinions are worth paying attention to. As a quote attributed to Lily Tomlin put it nicely, ‘the trouble with the rat race is that even if you win, you’re still a rat.’

In that spirit, I enjoyed reading the reminder in this picture. The quote is from Ichiro Suzuki, a baseball player (currently for the Seattle Mariners) and clearly a success in his field. I found Ichiro’s words printed on a Starbucks coffee cup, and fancied them even more than the maple latte inside. I hope you enjoy them too.

P.S.: Yes, I do more reading than just Starbucks cups.

Sir Arthur on TV

Last week I reread an old classic SF novel, and noticed some remarkable details in this passing comment by one character about the fictional 21st-century Utopia:

"… there are too many distractions and entertainments. Do you realize that every day something like five hundred hours of radio and TV pour out over the various channels? If you went without sleep and did nothing else, you could follow less than a twentieth of the entertainment that’s available at the turn of a switch! No wonder people are becoming passive sponges — absorbing but never creating. Did you know that the average viewing time per person is now three hours a day? Soon people won’t be living their own lives any more. It will be a full-time job keeping up with the various family serials on TV!"

Arthur C. Clarke, Childhood’s End, 1953

Of course, in this passing reference Clarke probably wasn’t trying to make a serious prediction. Nevertheless, Sir Arthur’s astute understanding of the future growth and effects of TV is impressive, all the more so given TV’s primitive state when he wrote that in 1953.

Some perspective. According to Wikipedia and TerraMedia, in 1953 the first commercial TV licenses were granted in the states of Arkansas, Idaho, Kansas, Maine, Mississippi, Montana, Nevada, North Dakota, Oregon, South Carolina, and South Dakota. Canada had only just begun its first regular TV transmissions the year before, and the states of New Hampshire, Vermont, and Wyoming wouldn’t issue their own first licenses until 1954. 1953 also saw the first TV coverage of the Academy Awards, and the launch of TV Guide.

How did Clarke do? With the benefit of hindsight, let’s see:

  • Three hours a day? Right on: A recent global study reported that the average TV viewing time per person worldwide is just over three hours per day. In the United States, it’s four and a half hours per day. The Japanese top the list at five hours per day.
  • 500 hours of content per day? Far more: At 16 hours per day, that would equal a mere 30 radio and TV stations. In 2006 the United States alone exceeded 2,200 TV stations and 13,700 radio stations. [CIA factbook] That’s not counting programming on "channels" like On Demand and YouTube.

As we often say today, "Who knew?" In this case, Sir Arthur did. Last month he turned 89, and his literary output is still going strong. Hats off to the man!