Sponsored Link •
Bill Venners: You mentioned scalability and versioning concerns with respect to checked exceptions. Could you clarify what you mean by those two issues?
Anders Hejlsberg: Let's start with versioning, because the issues are
pretty easy to see there. Let's say I create a method
foo that declares it throws exceptions
C. In version two of
foo, I want to add a bunch of features, and now
foo might throw exception
D. It is a
breaking change for me to add
D to the throws clause of that
method, because existing caller of that method will almost certainly not handle that
Adding a new exception to a throws clause in a new version breaks client
code. It's like adding a method to an interface. After you publish an interface, it
is for all practical purposes immutable, because any implementation of it might
have the methods that you want to add in the next version. So you've got to
create a new interface instead. Similarly with exceptions, you would either have to
create a whole new method called
foo2 that throws more
exceptions, or you would have to catch exception
D in the new
foo, and transform the
D into an
Bill Venners: But aren't you breaking their code in that case anyway, even in
a language without checked exceptions? If the new
foo is going to throw a new exception that clients
should think about handling, isn't their code broken just by the fact that they
didn't expect that exception when they wrote the code?
Anders Hejlsberg: No, because in a lot of cases, people don't care. They're not going to handle any of these exceptions. There's a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue. The programmers protect their code by writing try finally's everywhere, so they'll back out correctly if an exception occurs, but they're not actually interested in handling the exceptions.
The throws clause, at least the way it's implemented in Java, doesn't necessarily force
you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which
exceptions might pass through. It requires you to either catch declared
exceptions or put them in your own throws clause. To work around this requirement, people
do ridiculous things. For example, they decorate every method with,
throws Exception." That just completely defeats the feature,
and you just made the programmer write more gobbledy gunk. That doesn't
Bill Venners: So you think the more common case is that callers don't explicitly handle exceptions in deference to a general catch clause further up the call stack?
Anders Hejlsberg: It is funny how people think that the important thing
about exceptions is handling them. That is not the important thing about
exceptions. In a well-written application there's a ratio of ten to one, in my opinion,
of try finally to try catch. Or in C#,
using statements, which are
like try finally.
Bill Venners: What's in the finally?
Anders Hejlsberg: In the finally, you protect yourself against the exceptions, but you don't actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you've grabbed, and so forth. You clean up after yourself, so you're always in a consistent state. You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.