
The trouble with Checked Exceptions (C# architect) - davedx
http://www.artima.com/intv/handcuffs.html
======
gioele
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
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.

~~~
bunderbunder
There is one part of the idea that I'd like to salvage, though, and that's
having some clear documentation right there in the code about what kinds of
exceptions I can expect to see a procedure throw.

At the very least it'd be useful for when I'm wearing my "DLL author" hat,
since it'd give me an easy way to look through the public interface and make
sure exceptions won't be causing unrighteous leakage of implementation details
for the end-user. I'd rather not put users in a situation where they have to
look at the framework source in order to interpret an exception. It's kind of
irritating when that happens.

I think it's really not something that should require special language
statements, though. A static analyzer should be able to automatically figure
it out.

------
philbarr
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]

~~~
pohl
_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.

~~~
lsd5you
It depends what standards you hold the library to. Null pointer exceptions and
other runtime exceptions are can be treated as errors - something which needs
fixing in the code, rather than something that can be handled. A world of
difference.

~~~
pohl
And that is still the case with the Guava Throwables strategy, which only
effects how checked exceptions are propagated.

------
ZitchDog
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
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.

~~~
ZitchDog
_Checked exceptions require that the calling function acknowledge that an
error has occurred_

But why do they require the client to acknowledge the error? Better stated,
why would one use a checked exception versus an unchecked? The general wisdom
(and perhaps this is where I'm mistaken) is that checked exceptions generally
indicate a more recoverable error. This is why checkedness doesn't belong in
the function itself: it's an indication to the caller of the error's
recoverability, which is completely unknowable.

~~~
scott_s
Note that I was not arguing _for_ checked exceptions. Rather, I was arguing
that your argument does not support your conclusion.

With that said, I think it may be reasonable to say "You may be able to
recover from a missing file, but no one can help you if this pointer is null."
It's the difference between a logic error in the program (null pointer
exception, array out of bounds exception) and configuration errors (missing
file, lost connection). Checked exceptions are typically explicitly thrown by
the called function; unchecked exceptions are typically encountered because
the called function itself had an error. In other words, checked exceptions
are when the called function recognizes an error, and throws it up to its
caller.

So, I am able to distinguish them myself. But I'd still rather not have
checked exceptions. The mentality of "acknowledge all errors" makes more sense
in the error-code model, as seen in C programs. In that case, if you don't at
least check for and report all possible errors that can arise from calling a
function, then they will _never_ get reported, and your program will silently
be wrong.

~~~
ZitchDog
_Note that I was not arguing for checked exceptions._

Right, I understand that. And I was merely pointing out a flaw in your
argument against my argument.

 _You may be able to recover from a missing file, no one can help you if this
pointer is null_

My argument (which you seem to be doing a great job of ignoring) is that this
distinction is completely unreasonable. As the calling function, I am passing
in the pointer, therefore I am the only one who can know whether the null
pointer is a recoverable issue! Consider the ArrayOutOfBoundsException -
perhaps the array bounds are passed in from the user interface, and the error
should be trapped and reported to the user. This checked / unchecked
distinction is simply nonsensical from the called function's point of view.

 _Checked exceptions are typically explicitly thrown by the called function;
unchecked exceptions are typically encountered because the called function
itself had an error_

This is not typical, is not how you are using them in your examples, and also
makes no sense. What is the difference between encountering a particular error
within a function or a sub function? What if the logic in the function is
later extracted into a subfunction?

~~~
scott_s
I'm sorry if you feel that I'm ignoring your distinction. I'm not trying to
ignore it, but argue that I think we _can_ distinguish between "likely
recoverable" and "likely not recoverable" for _most_ cases. Nothing prevents
you from catching unchecked exceptions. So if you know that you're passing in
a may-be-null-pointer-and-it's-okay, then you can do an unusual thing and
catch that exception. I agree that we can't classify all exceptions as
recoverable or not recoverable from inside the called function, with full
accuracy. But I disagree that we can't make reasonable guesses that will be
true in most cases.

The function may encounter an error but it is not the caller's fault - that's
what I mean by "the called function itself has an error."

~~~
ZitchDog
Sure, we _could_ guess at all sorts of things from within a function. We
_could_ guess that the function is running from a terminal, and simply print
the result of the function to stout. Hell, we could guess what the caller is
going to do with the result of our function and just do that instead! Why even
have a caller at that point?

Of course I'm using hyperbole to point out the absurdity of making this
distinction, which on the surface may seem reasonable. The fact is, however,
the fewer assumptions a function makes about it's calling context, the better.
The whole point of functions is that they are to be reused in ways the author
may not have intended. The checkedness of an exception is an assumption about
the calling context of a function which should not exist.

------
AndrewDucker
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
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.

~~~
jsolson
> In my experience many C# programmers simply fail to add much exception
> handling code at all because the compiler doesn't force them to.

Still better than:

    
    
        try {
            // Do broken stuff
        } catch (Exception e) {
            throw new RuntimeException(e); // TODO: Add a domain-specific runtime exception so we can actually catch this
        }
    

I find this or something like it[0] spread across every Java codebase I find
myself mired in, and I read a _lot_ of Java these days (much to my dismay, but
so it goes).

[0]: Actually, that's not fair. Most people don't bother to include the TODO.

~~~
Roboprog
You meant to say "catch (Throwable e)", right? But, yeah, I've had to write
that block too many times.

Throwable will catch Errors as well as Exceptions, such as when a constructor
called from a dependency injection framework fails. It's kind of irked me for
a while that I had to know that. I would have rather had "catch" work on
_anything_ , with the option to check the class and rethrow once in a great
while. That is, in the few places where the error checking/logging actually
belongs (as stated in the article, with which I obviously agree).

There is indeed great irony in Java code littered with catches, which then
falls out and kills the main loop without logging anything. (I recently had to
diagnose such a case in a system at work over the phone -- sure enough, that's
exactly what was coded)

~~~
sixcorners
You are not supposed to, and don't need to, catch Errors. The only exceptions
you need to worry about as far as checked exceptions go are classes that
inherit from Exception but not RuntimeException.

------
philf
> 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
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?

~~~
specialist
"the only sane way of working with it is to subvert it."

Perhaps.

In my projects, I use wrapped exceptions to convert "what blew up" exceptions
into "what to do about it" exceptions. A poor man's event routing. For
example, I wrote an ETL workflow thingie that would retry, reset, restart,
backoff (throttle) depending on what was failing.

I'd be totally game for pre declaring what exceptions your code will catch,
harkening back to the days of "on message do this" type programming. Then the
compiler can tell verify that all the thrown exceptions get caught by
somebody.

Meanwhile, I've never had a problem with checked exceptions.

Methinks the real cause of angst over checked exceptions are all these
mindless frameworks, APIs, libraries, strategies, design patterns, aspects,
inversion of common sense, injection of nonsense, etc.

The complexity borne of the manner in which Spring, JPA, Hibernate, connection
pooling, aspects, MVC, blah blah blah attempt to hide, obfuscate, decouple,
mystify, pseudo architect "solutions" ... well, it's just insane.

Someone upthread off-handedly noted the irony of declaring all these
exceptions only to have the main event loop eat an exception without any
logging. Story of my life. Debugging silent death failures really, really
sucks.

Which is why I work as "close to the metal" as possible and worry not about
unchecked exceptions.

------
kbd
For old articles, please put a date in the title. In this case, (2003).

~~~
AndrewDucker
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.

~~~
sirclueless
That's all the more reason to put the date there. It signals an article that
is relevant today despite being almost ten years old. The argument is
considerably more impressive when you realize that it happened ten years ago
and is still relevant, but I didn't know it was a timeless classic until I saw
this comment thread.

------
Uchikoma
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
The Java Programming Language's checked exception feature is fundamentally
broken. All newer Java specifications have acknowledged this and utilize un-
checked exceptions.

~~~
tomjen3
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
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
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.

~~~
udp
It reminds me more of C, where labels and goto are often used for error
handling (labels using the same `:` syntax).

~~~
ajitk
Now that you you mention labels, I see the similarity to C. I might have been
influenced by OP's reference to use _indentation_ to make code more readable
instead of using braces.

------
bokchoi
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
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
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
Exceptions are a bad idea. Even in the more saner languages such as python,
they tend to obfuscate needlessly.

~~~
je42
so you prefer to decentralize your exception handling code ? how do you scale
that ?

~~~
dscrd
The problem is that when exceptions are available, people will start using
them for non-exceptional things and (the worst case) basic control flow.

Case in point from a popular framework, Django: the standard way of getting an
object from the DB via the ORM is Class.objects.get. This method either
returns a single object or raises on exception if there are zero rows in the
db or another exception if there are two or more rows. It may also raise other
kinds of exceptions.

Now, it's clear that having zero rows is not very exceptional, and even >1 is
somewhat debatable. Note especially that this is not just some weekend project
by a nobody, it is a framework that is widely used and respected.

~~~
Ingaz
>> and (the worst case) basic control flow. I call it "java-way goto"

I can't agree about Class.objects.get - method must return exactly one row by
known pk value.

So it perfectly sane to raise exception for zero rows.

Class.objects.filter is working the way you want.

~~~
dscrd
Except that get accepts as parameters non-unique non-primary fields too.

I have every reason to believe that the Django devs are capable people who
thought about this and landed on this specific usage with a clear rationale...
but it still is a misuse of error handling capabilities of a language. And a
sort of misuse that everyone else does sometimes as well.

