top | item 4017686

The trouble with Checked Exceptions (C# architect)

51 points| davedx | 14 years ago |artima.com | reply

76 comments

order
[+] gioele|14 years ago|reply
The crux of the question:

> Bill Venners: But aren't you breaking their code in that case anyway, even in a language without checked exceptions? If the new version of 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 help anybody.

[+] paol|14 years ago|reply
Exactly. I think the 2 key failings of the checked exception idea (there are others, but not as important) are

1) Precise exception specifications leak implementation details. This will bite you badly, e.g., when you want to change the implementation from under a published API.

2) The times when we only care that some exception occurred vastly outnumber the times when we care about the exact types of exceptions that may occur. Checked exceptions don't add any value to the common case, in fact they make it worse, because generic exception handlers tend to live many levels up the call stack from where exceptions are thrown(1), and therefore they "aggregate" large amounts of code that that can collectively throw a huge range of exceptions. If you were to carry around detailed "throws" clauses, they would be a mile long.

The funny thing is, all solutions that solve the problems created by checked exceptions do so by subverting the mechanism one way or another. So you're better off without checked exceptions in the first place.

I've always been interested in this discussion because it's one of those cases where an idea seems very good on paper, only to turn out quite bad in practice.

(1) This observation is what makes exceptions such a useful mechanism in the first place.

[+] ams6110|14 years ago|reply
I'm in Hejlsberg's camp on this. Exceptions should rarely be handled. If a non-happy-path use case causes exceptions, you're doing it wrong: exceptions should not drive your program logic; you should be proactively checking or guarding for those conditions. Exceptions are for things you didn't foresee, and ergo are not anything you're going to be able to "handle" other than by bailing out as cleanly as possible.
[+] philbarr|14 years ago|reply
As a long time Java programmer, who has been writing C# for the last year and a half, I think leaving out checked exceptions from C# may have been a bad idea. What they've done is to identify that checked exceptions are a pain in many cases and simply removed them without providing a proper replacement. This particular quote demonstrates what I mean:

"To work around [the need to declare what you intend to do with each exception] 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 help anybody."

Ok, so what you did instead was to effectively put "throws Exception" on every method by default. You actually implemented the workaround you've just criticised into the language?

And what's the effect of this - whenever you call a method in an API, you have no idea what could go wrong with it, so you can't write code to handle it. It wouldn't be so bad if a method's potential exceptions were documented, but they never are. So you end up in a situation where you just code for the simple "happy case", run it, see what breaks, put some exception handling in (for just Exception) where you can, run it again, etc. It's a dreadful way to write code.

I'm not saying Java's checked exceptions were great - far from it - but C#'s "solution" is terrible. The number of times you end up with a NullException because some method failed somewhere deep in your code and something else didn't get initialised is unreal. If you don't believe me, try working with Sharepoint for a few minutes, and that's Microsoft code.

[edit - spelling]

[+] DrJokepu|14 years ago|reply
He addresses your point in detail in the interview:

C# is basically silent on the checked exceptions issue. Once a better solution is known—and trust me we continue to think about it—we can go back and actually put something in place. I'm a strong believer that if you don't have anything right to say, or anything that moves the art forward, then you'd better just be completely silent and neutral, as opposed to trying to lay out a framework.

...

I'm a strong believer in being minimalistic. Unless you actually are going to solve the general problem, don't try and put in place a framework for solving a specific one, because you don't know what that framework should look like.

[+] pohl|14 years ago|reply
Ok, so what you did instead was to effectively put "throws Exception" on every method by default.

That implicit throws clause was already there in any language that contains unchecked exceptions for things like dereferencing a null pointer, or assertions, etc. So, no, that's not what removing checked exceptions does. Personally, I'm a big fan of Guava's Throwables class. The java I write these days transmutes all checked exceptions into unchecked wrappers at any API boundary that tries to force them on me. And, no, this doesn't mean I'm only coding for the happy case. Rather, I'm choosing where and how to handle the sadness.

[+] rpsw|14 years ago|reply
I can't help feel that warnings and/or a strict mode to enable something similar to checked exceptions would be of help for those that wanted it.

Regarding null exceptions, they are runtime exceptions in Java so it's much the same there. It would be very annoying if they were checked exceptions.

[+] ZitchDog|14 years ago|reply
I have thought quite a bit about checked vs unchecked exceptions and come to the realization that there is a fundamental philosophical problem that checked exceptions can never overcome.

The idea with checked exceptions are that they should be used for errors which the caller should be forced to handle. But this property is entirely dependent on the context the function is being called from! For example, if the user is specifying a filename for a file, I should be expected to catch the error and display feedback to the user. However, if I just wrote the file to disk 5 seconds ago, I shouldn't be forced to trap the error!

The crux of the problem is this: the severity and recoverability of an error is known only by the caller of the function, not the function itself. Checked exceptions attempt to foist this information into the function itself, where it is unknowable and generally inaccurate. Checked exceptions are a misfeature if I ever saw one.

[+] scott_s|14 years ago|reply
I agree with the C# designers' reason that checked exceptions are not a good idea, but I don't agree with yours. In other words, your argument is different than theirs, and I don't agree with it. (Although I still agree with your conclusion.)

The crux of the problem is this: the severity and recoverability of an error is known only by the caller of the function, not the function itself.

I agree with that statement, but not that it is the crux of the problem with checked exceptions. That statement is an argument for general error reporting - it need not even be exceptions. Simply, the function that encountered the error does not know what to do about it, so it must report it on up the stack. We could just as easily accomplish that with error return values - I'm not saying we should, just that I think your argument is too generic to support your conclusion.

Checked exceptions attempt to foist this information into the function itself, where it is unknowable and generally inaccurate.

And that I actually disagree with. Checked exceptions require that the calling function acknowledge that an error has occurred, it does not require the calling function to handle the error. The calling function could easily catch the exception and rethrow it, or just add the exception to its own throws clause.

The C# designers' argument is that what I described is generally what people want to do, so why not just make it the default? That default is unchecked exceptions.

[+] evincarofautumn|14 years ago|reply
I don’t see how checked exceptions impose decisions of severity & recoverability on a function. If you are a function, exceptions are how you notify your caller that something has happened for which you are not responsible.

Checked exceptions are not about imposing responsibility, but about disclaiming it and deferring it to a higher authority in a type-safe manner. And the issue seems to be more syntactic than philosophical; Haskell models checked and unchecked exceptions as a monad (or as a monad transformer for running exceptional code in another monad) and it feels very natural.

[+] beersigns|14 years ago|reply
I agree with you but converting the masses, especially in the workplace, is tough.
[+] AndrewDucker|14 years ago|reply
I am _very_ glad that C# does not have checked exceptions. Anders is completely correct in that the vast majority of the time individual methods do not handle specific exceptions, they just roll things back and pass the exception up the way. Adding exception attributes in all of these places would be a massive pain.
[+] thebluesky|14 years ago|reply
In my experience many C# programmers simply fail to add much exception handling code at all because the compiler doesn't force them to. The net result is code which breaks in spectacular fashion when the first unexpected condition is met.

Checked exceptions are a nuisance (I'm actually glad Scala doesn't enforce them vs Java), but often leads to inexperienced C# devs writing very fragile apps.

With C# you have to examine docs and source to identify exceptions which could be thrown. Many programmers don't bother, leading to things breaking. In Java the compiler forces you to think about it. I'm not in favour of checked exceptions, but the arguments against them tend to be a bit simplistic.

[+] TazeTSchnitzel|14 years ago|reply
The reality is that programmers do not have the time to handle every single possible exception. I reckon every few function calls you make could potentially trigger an exception. You generally just have a catchall (or not, and let the program abort), and then catch certain specific exceptions that are common enough.
[+] sixcorners|14 years ago|reply
Attributes? Why not just

throw new RuntimeException(exception);

Edit: If there weren't exceptions for every mundane thing I think I would prefer no checked exceptions also.

[+] philf|14 years ago|reply
> You end up having to declare 40 exceptions that you might throw. And once you aggregate that with another subsystem you've got 80 exceptions in your throws clause. It just balloons out of control.

What he completely ignores is the possibility to wrap exceptions to either aggregate them or to convert them into unchecked exceptions.

[+] paol|14 years ago|reply
But that's exactly one of the main points of the detractors of checked exceptions (of which I'm one): the only sane way of working with it is to subvert it.

Whether you convert the throws clause to a common supertype (which very soon converges to the base type Exception), or wrap everything in a RuntimeException, you are effectively emulating a language without checked exceptions. So what was the point in the first place?

[+] thebluesky|14 years ago|reply
Exactly. I've been using Java for 13 years and have yet to see a method signature with more than a handful of exception types thrown, let alone 40 or 80. I've told you a millions times not to exaggerate ;)
[+] kbd|14 years ago|reply
For old articles, please put a date in the title. In this case, (2003).
[+] AndrewDucker|14 years ago|reply
If it was something that was time-dependent, I'd agree, but in the case of an interview talking about the design of two languages in current use,it's timeless.
[+] Uchikoma|14 years ago|reply
Checked exceptions are fine.

The problem is, that they are not composable and most languages have no syntactic sugar for dealing with them as Monads.

Other checked error mechanisms like Either or are much easier to manage.

I do hope e.g. Java sometimes in the future gets syntactic sugar to deal with checked exceptions as Monads.

[+] lenkite|14 years ago|reply
The Java Programming Language's checked exception feature is fundamentally broken. All newer Java specifications have acknowledged this and utilize un-checked exceptions.
[+] tomjen3|14 years ago|reply
All but one (and arguably the most important) Android.

Android is full of brand new checked exceptions.

And I do what I always do with checked exceptions:

    catch (e) {
      throw new RuntimeExeception(e);
    }
(you can't keep adding throws clauses because the compiler won't let you add them if the interface you implement can't handle them).
[+] rvkennedy|14 years ago|reply
I have long wondered about the syntax of exceptions - if it was:

  void function()
  {
  try:
    function_body...
  catch(Exception e):
  finally:
  }
By leaving the function body in the same indentation as it would be without exception handling, this might help to make the code a little more readable than:

  void function()
  {
    try
    {
      function_body...
    }
    catch(Exception e)
    {
    }
    finally
    {
    }
  }
[+] ajitk|14 years ago|reply
My mind parsed the first code block as a mix of Python and C. IMO, the later would be more readable since it involves parsing only one rule that the eye is already used.
[+] AndrewDucker|14 years ago|reply
That would be useful if you only need a try/catch at method level. If you need two try/catch chunks in a method then that wouldn't work.

I do agree that having try/catch at method level would be useful in many ways - as an additional piece of syntax.

[+] bokchoi|14 years ago|reply
I tend to agree that Java's checked exceptions are annoying (hello SQLException). However, when I used C# I was annoyed that the VS intellisense and the C# generated documentation didn't tell me what exceptions might actually be thrown! In practice this meant just not handling anything at all.
[+] darrenkopp|14 years ago|reply
That's because the developer didn't put the exception into the documentation. But at the same time you really shouldn't rely on that because something down the line could throw an exception that isn't covered in the documented exceptions.
[+] viraptor|14 years ago|reply
The thing that really annoys me about checked exceptions is that map/reduce/fold like functions throw anything by definition. Basically as soon as you allow any general type function as a parameter, you need to mark yourself as throwing everything.

That is really limiting in some scenarios.

[+] dscrd|14 years ago|reply
Exceptions are a bad idea. Even in the more saner languages such as python, they tend to obfuscate needlessly.
[+] je42|14 years ago|reply
so you prefer to decentralize your exception handling code ? how do you scale that ?