Live data from Hacker News

Why checked exceptions failed

borretti.me

261–270 of 318 posts

Re: Why checked exceptions failed

#261

Earlier quoted context omitted.

> But importance of the failure is determined completely by the program, not the library. Exactly. I think this is the real crux about what's wrong with checked exceptions. It puts the responsibility to decide what exceptions are important on the library, where it doesn't belong. Only the user of the library knows that.

Isn't it exactly the opposite? Checked exceptions are for libraries to declare "exceptions" they can't handle themselves. You, the user of the library, have to deal with them (or declare them checked yourself¹). I'm not a friend of checked exceptions myself, but I still think it's the opposite. ¹ which leads to the real issue with checked exceptions: they propagate through dependencies, if one nested dependency adds…

I don't think we disagree it's just a different perspective. The forced handling or propagation is what makes them annoying, but I think they're conceptually wrong.

It would be another matter if they were designed such that you could fix an issue and continue the call on the happy branch, but I suspect the cases where something like that would be applicable are very few.

Re: Why checked exceptions failed

#262

Earlier quoted context omitted.

Or I can catch any exception out of the codepath I'm concerned about, examine it to see if it's one of the known set of exceptions I intend to handle, and then either do so or rethrow it. If there's a benefit to compile-time exception checking over this method, I have to admit I don't see it. But I've also never worked deeply enough with Java to be familiar with the nuances of its exception handling, so that may be w…

The problem is that handling arbitrary errors can be very complex. It's easy to make errors in the error handling code. Especially if the error you are handling never occurs -- because there's no way to test error handling code for an error that never happens. That's why it is really useful to know when a call can fail, and what kinds of errors you have to expect. If you always have to add a generic error handler for…

> Especially if the error you are handling never occurs -- because there's no way to test error handling code for an error that never happens.

Sure there is. Find the way it happens, do that, and test that the handler does what it's supposed to. Or, if you can't do that, mock the error.

I suppose that's not guaranteed to be straightforward in Java; it's been a long time but I seem to recall libraries being provided in compiled form, without sources, and it therefore not always being possible to identify the conditions that need to be set up in a unit test. If I recall that correctly, it makes me very glad I no longer use the language.

> If you always have to add a generic error handler for possible unknown errors, then you'll write a lot of untested, dead code.

The generic handler in this case is

    else {
      throw error; // rethrow
    }
You're not wrong that there's value in knowing what exceptions can be thrown at a given point in code. But, as I mentioned in another comment, that's something that can in the general case be known through static analysis, and should. In fact, the Java compiler must already be doing something substantially similar to that analysis for checked exceptions to work at all! Looking for throw statements rather than "throws" declarations seems like it shouldn't be that much more difficult, and I think the burden on Java developers could be substantially lightened thereby in that "throws" declarations would no longer be required.

Re: Why checked exceptions failed

#263

Checked exceptions failed because 99 times out of 100 the exception is not recoverable, so the try/catch block is just wasting everyone's time. (In 7 years as a Java dev I can think of one time I wrote code that tried to recover from IOException instead of just making the caller retry.) Even when the exceptions is theoretically recoverable, it has to get propagated up properly to the caller who should be handling rec…

I don't think they are meant to be recoverable from, but instead they are a way to provide a controlled shut down of an irrecoverable failure, or to limit the blast radius of a localized failure. In that sense, they are quite useful. Saving the file generated an exception - instead of suddenly closing the application, display an error. Or maybe a database is not accessible anymore. Instead of suddenly ending the serv…

In a desktop application that is not allowed to totally crash, or at least has to crash kind of gracefully, checked exceptions are useful.

But in the world that most Java devs live in, which is various flavors of RPC server, failing requests is fine. If lots of requests fail, your monitoring infra should page someone, and that someone will go log spelunking and figure out what's broken.

Very occasionally it turns out that the thing causing the RPC failures is a recoverable exception, and then you should wrap the problematic stuff in a try/catch block. (Often you'll wind up having to detect the recoverable error case by conditioning on substrings in the exception message, which the library owners will arbitrarily change in future releases. So make sure to write regression tests so you'll catch this when you upgrade the library. Java is fun!) But 99% of the time the failure is "network is busted" or "config was invalid" or "hard disk failed" and you should not be defensively programming against all those possibilities.

Re: Why checked exceptions failed

#264
post #165

Earlier quoted context omitted.

I misspoke. Ignoring the syntax for a moment, I want scoping to behave like this pseudo-code. So that the catch and finally blocks are lexically nested within the parent try block. try { OutputStream out = ... ... // Must be at end of try block catch ExceptionA, Exception B { ... } catch Exception C { ... } finally { ... } } // end of try Maybe even allow catch and finally to allow single expression in addition to bl…

Right, but if constructing OutputStream throws ExceptionA, you shouldn't have it in scope; it's not something you can use.

Agreed. I'll make that more clear next time. I omitted catch's parens, which makes it less clear.

I just want 'out' visible to both catch and finally.

Re: Why checked exceptions failed

#265

Earlier quoted context omitted.

Checked exceptions should be the default, exceptions should just be rare. They are overused in almost all languages.

The fundamental thing an exception does is allow you to choose where in the stack to react to the exception. The fundamental thing a checked error does is force you to actually choose (even if that choice is to bubble all the way up and crash the program), rather than forget and end up with a bug. The choice about where to handle the exception is almost always a good thing, since it reduces boilerplate in dealing wit…

I think there are idioms where your unchecked exceptions can be caught, like via some scoped context, like an actor.

Re: Why checked exceptions failed

#266

Earlier quoted context omitted.

The fundamental thing an exception does is allow you to choose where in the stack to react to the exception. The fundamental thing a checked error does is force you to actually choose (even if that choice is to bubble all the way up and crash the program), rather than forget and end up with a bug. The choice about where to handle the exception is almost always a good thing, since it reduces boilerplate in dealing wit…

I think there are idioms where your unchecked exceptions can be caught, like via some scoped context, like an actor.

Yes, that's intentional. They are still exceptions because there are rare cases where you want to catch them. They're unchecked because it's not worth the hassle of declaring them everywhere. Python's KeyboardInterrupt is another great example -- it can theoretically happen almost everywhere, but most scripts don't have anything sensible to do with it and it will never happen in a daemon or GUI program. If you happen to be writing a REPL, though, it could be useful to just interrupt the last command.

Re: Why checked exceptions failed

#267

Earlier quoted context omitted.

It is dangerous to call a method on an object whose type is not being checked by the compiler. Whether that's a ridiculous thing to worry about depends on how important your program is. If you work for NASA and your code will run inside the Mars rover, it is not ridiculous to worry about such things, but if you're writing some code that will be used once and thrown away then yeah, it might be ridiculous.

It is being checked by the compiler though. For your example to work both would need to extend a common object (unless the only thing you ever do to that object is call fire(), which is nonsensical) or you would get a compile time error right off the bat. It's a ridiculous thing to worry about in either of your cases. That incredibly specific situation simply isn't ever going to happen in practice because so many oth…

> For your example to work both would need to extend a common object

Not necessarily at all.

> unless the only thing you ever do to that object is call fire(), which is nonsensical

In this example, when the object is returned by a particular method, only fire() is being called, but other ways of obtaining the object can have more methods being called.

> It's a ridiculous thing to worry about in either of your cases.

Not at all... if your program is running inside a NASA rover, or if your program is running inside a robotic surgery machine you have to worry about safety and you want to maximize compile-time checks.

Re: Why checked exceptions failed

#268

Earlier quoted context omitted.

I don't think they are meant to be recoverable from, but instead they are a way to provide a controlled shut down of an irrecoverable failure, or to limit the blast radius of a localized failure. In that sense, they are quite useful. Saving the file generated an exception - instead of suddenly closing the application, display an error. Or maybe a database is not accessible anymore. Instead of suddenly ending the serv…

In a desktop application that is not allowed to totally crash, or at least has to crash kind of gracefully, checked exceptions are useful. But in the world that most Java devs live in, which is various flavors of RPC server, failing requests is fine. If lots of requests fail, your monitoring infra should page someone, and that someone will go log spelunking and figure out what's broken. Very occasionally it turns out…

> you should not be defensively programming against all those possibilities

This is where libraries and frameworks come into play - they defensively program against that for you. And wrap it all up in a simple interface with, well, checked exceptions.

Re: Why checked exceptions failed

#269
post #18

While I broadly agree with this, the author doesn't appear to go far enough himself. > Functional error handling, using Option and Result types, is rapidly becoming the standard operating procedure in essentially every language, because it relies on nothing but values and types. They are more of the same, and so they fit right into the existing language machinery. I agree that Optional types are better than checked e…

The problem with union types for exceptions is that it becomes impossible to return an error as the correct case, or at least there is no way to discriminate any more. Functions that deal with errors also need to be able to have exceptional situations, and in many cases there are completely generic functions as well that can error out for generic reasons. A basic example is the elementary case of having a list of err…

> And there's a good reason almost no statically typed language has support for union types

For what it's worth, I learned about union types from Ceylon, which was statically typed.

Re: Why checked exceptions failed

#270

Earlier quoted context omitted.

You must have a real panic when you see a sign saying “No parking except weekends.” Weekends happen all the time!

So if you write code that handles dates you'd throw NotWeekendException to notify the caller that it's not weekend? Exceptions should be for exceptions, not control flow.

I'm curious how this is possible? Exception throwing and handling is fundamentally a flow control construct. ie: throwing an exception must control flow. A counter-example snippet where throwing an exception does not control flow would be appreciated.
Post reply on HN