I hate unchecked exceptions


Well, actually, I don’t hate them at; i just hate not having any tools to tell me what exceptions could get thrown on the calls I make.  Of course I realize how that might not be possible to compute given that you really don’t know what could happen with a virtual call, however i still think a lot of useful information could be given.   You could certainly start by marking any method that actually throws an exception (which escapes the method) with the information about that exception.  You could then take the transitive closure to determine the extent that those exceptions could reach.  You could use that information to make sure that the doc comments for methods didn’t forget to mention those exception, and you could also use preexisting <exception> tags to augment the scanner for methods that could not be determined automatically.

I’m also not convinced of the problems that Anders’ raises here.  However, I don’t have enough experience with large scale applications to know whether or not exceptions work well in those situations.  I do know I’ve seen checked exceptions horribly abused (i.e. catches that, innapropriately, swallow exceptions.  every methods decorated with “throws exception”).  Of course, in the past I’ve stated that sometimes it’s good to not have a features if its going to be abused and people have lambasted me for that.  Now it appears I’m going to be hypocritical by saying that I think in this case we should have a feature even if it can be abused.  However, i think that because it seems like it’s so beneficial, and even if it’s abused it’s no worse than our current system.  Of course, I do understand Anders when he says “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.”  However, it’s been a few years since the inception of C# and no perfect solution has been found, so maybe it’s time for just something that makes things better.

I’d really like to work on something that could go and analyze existing code/metadata and garner this information for the user.  I think it would be helpful and it would certainly be great for learning how to read and examine IL instead of just producing it.  Of course… now I just have to find the time to do so :-/


Comments (22)

  1. James Snape says:

    Hi Cyrus,

    I recon it doesn’t need to be anything so grand. When I’ve written a function call I then go "Hey, I wonder what exceptions I’ve got to deal with?". If the function is listed in the online help then you can use that as a guide – but it doesn’t list _all_ the exceptions for that function. If it’s not listed then you are stuck.

    What would be useful is just a little window that listed all the exceptions thrown from a particular function. Click on the function to see the list.

    Mind you, I guess once you have the code to grap this information for the IL/Metadata then it should be pretty trivial to insert it into the intellisense system. Type "catch (" and get a list of possible exceptions thrown. That would be cool.

    Regards,

    James.

  2. Dr Pizza says:

    "I’m also not convinced of the problems that Anders’ raises here. "

    Then, to be honest, I can only assume you’ve never done any significant amount of work in the 1 language that offers the kind of checked exceptions I think you want.

    Checked exceptions are abused. That alone is not a good reason to not have a particular feature. The problem with checked exceptions is that you have no /choice/ but to abuse them. The entire point of an exception is to allow you to separate error-handling and main control flow; to allow the error-handling to be somewhere appropriate rather than scattered over the main path through the application. Checked exceptions make that nigh impossible; you’ve either got to handle exceptions inappropriately or you’ve got to annotate every fucking method with an exception specification.

    And because you don’t want your interface to be bound to any particular implementation, you’ve got to wrap any exception you want to put in an exception specification with your own wrapper. You don’t want, for example, to throw "SQLException" because that way you’re forced to use a database; you might want an implementation that throws "IOException" instead. So you’ve got to wrap both these exceptions in something useless like "DrPizza.DataLoadException" and leave your caller clueless as to how to deal with the exception. Sure, you might throw a specific subclass of that (DrPizza.SQLLoadException, DrPizza.FileLoadException), but you can’t document that in the interface (because the number of subclasses of DataLoadException is unbounded), so you still can’t tell your caller what kind of exception you might be throwing.

    Exception specifications /don’t/ make things better.

  3. James: Yup, that was definitely an application that we were considering in the IDE. Another was to warn you if you didn’t catch an exception or declare that you threw it.

    BTW: We do now show you the exceptions that the user documented his type with. Of course that puts the burden on the API developer to get those right (not that hard) and to maintain them (which can be very difficult). I’ve gotten many exceptions thrown that were never declared anywhere πŸ™

  4. James: Yup, that was definitely an application that we were considering in the IDE. Another was to warn you if you didn’t catch an exception or declare that you threw it.

    BTW: We do now show you the exceptions that the user documented his type with. Of course that puts the burde n on the API developer to get those right (not that hard) and to maintain them (which can be very difficult). I’ve gotten many exceptions thrown that were never declared anywhere πŸ™

  5. David Levine says:

    You raised an interesting subject – I’ve made some suggestions along the same lines as yours and never heard a peep back about it. There are numerous problems with the current situation – it’s impossible to look at a single method and determine all the possible exceptions that it can throw, there is no way to look at exceptions from a high level and determine where a thrown exception will be handled.

    Also, unlike method signatures there is no contract that defines what can be thrown. I know this sounds like an argument for checked exceptions but it is not. I don’t like checked exceptions for some of the reasons you mention, but also because any method that relies both on external documentation and developer discipline is bound to fail – too many manual tasks must be done perfectly for it to work reliably. It must be generated automatically for it to be correct.

    My idea goes along the lines of having the compiler analyze the code and emit metadata that describes all the exceptions that a method body explicitly throws – if it is thrown by a called method it is ignored. It would have to account for transforms (an exception thrown in a method that is caught within the same method and possibly rethrown as some other exception type) and related issues. This data should be baked into the metadata for the method.

    It should also be possible (though difficult) to write a tool that analyzes/probes a call chain to aggregate all the possible exceptions that a given method call can throw by analyzing the IL and the metadata of the called method. There are problems examining the call chain when calling through virtual methods, via reflection, or by p/invoke – it might have to terminate the analysis at that point – but it would still deliver more information then is currently available. There could be ways to indicate that the search was terminated due to some issue like this; it will require some thought to figure out how best to handle the different situations. But at a mininum it would still yield the exceptions that the called method itself explicitly throws.

    Another aspect of this is the effect of an exception. If an exception is thrown, where is it handled? How does a designer "know" where a thrown exception will be caught? There is no tool that I am aware that even begins to analyze this. Most devs think of and design for the normal code path, and they can visualize the blocks that comprise a section of code, but the corresponding analysis for the exception path is usually not well thought out, if it is thought out at all. For small systems this is not much of a problem but for complex systems containing multiple component hierarchies this becomes a non-trivial problem, and it should be modeled as part of the overall system architecture. And then there are unhandled exceptions…but that’s another subject.

    Methods are a bi-directional channel specified by contracts – arguments can move in both directions; exceptions consitute a uni-directional channel that flows back up the call chain with no contract – anything can be thrown. This chain should be as carefully designed as any other part of a system but the tools to aid in this are non-existent.

    I’d sure like to see more work done on tools in this area – I think it’s wide open for improvement and there are a lot of opportunities here for third parties.

  6. Dr.Pizza: I thin kyou and I are in agreement here. As I explicitly stated, I dont’ really hate unchecked exceptions, and I don’t have enough experience to feel that checked exceptions are a suitable answer.

    What I do know is that currently it’s quite difficult to deal with the situation today and I’d like it to be better. because I don’t feel checked exceptions are necessarily the right way to go (and i definitely don’t feel taht i could get the change through the language and then possible enforced by the runtime (which is a good thing since, as you stated, there are so many issues with it)), i would like alternative ways to address the shortcomings of the current system.

    I feel you’re taking my one point out of context. I dont’ mind that checked exceptions force you to annotate methods. Personally I feel that the exceptions thrown _are_ part of the contract of a method and thus annotating them is not such a bad thing. That way if you do need to add an exception in the future it is a breaking change that your clients will know about. Nowadays it’s far too easy for someone to make sure a change and to end up breaking clients unexpectedly (no pun intended). *However*, to be totally clear, that doesn’t mean that I think checked exceptions are good, or the right way to go. I recognize the shortcomings, especially wrt interfaces. i would just like to see *anything* to help out here.

    Note: "help" refers both to helping out the API consumer to let them know what to expect, and "help" refers to helping out the APi producer to help them maintain their documentation

  7. David++

    πŸ™‚

    Dr.Pizza: I want to add this:

    I feel completely like a noob when it comes to error handling in programming. I don’t feel like I do a godo job of i today and I consider the problem to be one I really need to work on. it’s probably something I’ll talk on later as I want to do a better job on it with the next project I work on.

    As david said, one of the main problems is that the error path is usually not something that a lot of thought necessarily goes in to (probably due to programmer laziness) and that is pretty serious IMO.

    If you have resources that I could look into to help with this I would very much appreciate hearing about them.

  8. Ding says:

    How did I ever know that Mr. Bright would be replying to this topic..?

  9. Dr Pizza says:

    "What I do know is that currently it’s quite difficult to deal with the situation today"

    What, specifically, is hard to deal with? Your documentation generating tool can describe almost any exceptions thrown (and it can describe them automatically; it can see any "throw" clause and it can see any function calls, so it can see most exceptions thrown; the only difficulty would be doing something like loading or constructing a class at runtime), so if you want it written down somewhere, you got it.

    "I feel you’re taking my one point out of context. I dont’ mind that checked exceptions force you to annotate methods."

    I do. It makes your code very brittle. It means you’ve got to annotate each and every method in the call stack just to indicate that you don’t care about a particular exception. If you then change what goes on deep inside (say, switching from something that works off a file, and hence throws file exceptions, to something that works off a database and throws DB exceptions) you’ve then got to change all those annotations all the way through your program.

    "Personally I feel that the exceptions thrown _are_ part of the contract of a method and thus annotating them is not such a bad thing. That way if you do need to add an exception in the future it is a breaking change that your clients will know about. Nowadays it’s far too easy for someone to make sure a change and to end up breaking clients unexpectedly (no pun intended). *However*, to be totally clear, that doesn’t mean that I think checked exceptions are good, or the right way to go. I recognize the shortcomings, especially wrt interfaces. i would just like to see *anything* to help out here. "

    Exception specifications of the kind you want just don’t play at all nicely with interfaces. You can’t put the spec on the interface (or else you have the same problems as Java’s OutputStream has) but equally you can’t put them on implementations of the interface (because exception spec mismatches prevent methods from being overrides).

    And to be honest, I really don’t think it’s that useful. Even if you know what exceptions are going to be thrown, it’s relatively rare that you’re actually in a position to do anything useful with the knowledge. Java, for example, throws SQLExceptions for most JDBC operations. But in most cases there’s nothing of any value that you can do when you catch such an exception, because it could have been caused by just about anything. In the overwhelming majority of cases, there’s no real way of knowing, and nothing you can do to fix the problem. Another example, is OutputStream, again. Its close() and flush() methods can both throw. But what the /hell/ can you do in response? You don’t–and can’t–know why it can’t be closed or flushed. The documentation value of such annotations is nil. That they force you to catch these exceptions you can’t deal with is just salt in the wound. The entire mechanism is pointless.

    Apart from anything else, genuinely recoverable exceptions seem to be extremely rare, and probably shouldn’t be reported as exceptions anyway, as they’re just not that exceptional.

  10. AndrewSeven says:

    I often work with CommerceSevere and end up wondering what exceptions the CS objects will throw so that I can only catch those specific ones.

    I don’t think showing what the developer documented is really important, what would really help is to have an analysis tool in the IDE.

    (Three days without posts, I thought you had gone on vacation or something πŸ˜‰

  11. Dr Pizza says:

    "Ding: Mr. Bright? "

    Me.

    Long-time checked exception hater, as anyone who reads the threads in Programmers’ Symposium knows.

  12. Having worked on large Java apps (and been introduced to ones that are were already huge), there’s a tendency to both "throws Exception" and also "catch (Exception)". While the throws is much less of an issue with an IDE like Eclipse (where an exception throws, is not handled, and not in the throws clause just gives you a little light bulb with "Add throws" and "add try/catch", etc., and you typically just click "add throws"), the catch (Exception) is a bigger issue.

    The scenarios I’ve seen are often focused on conceptual boundaries (sometimes they’re also other kinds of boundaries, physical, transactional, COM, whatever), and one of the goals was that each method should catch all exceptions, do whatever local cleanup they needed, then rethrow – a lot of time that meant catch (Exception e) { do_cleanup(); throw e; } (Java doesn’t have just "throw", or at least didn’t in 1.4) – that really sucks, because the compiler only knows that Exception is getting thrown – if you hadn’t done the try/catch, it could have potentially known (again, Java kind of realm) that FileNotFoundException, SoapException, and InsufficientPermissionException could be thrown, but now you’ve gone and ruined that. You could have broken out 3 different catch blocks and saved that information, but that’s developer burden to help the compiler. That sucks.

    One of the intermediate approaches was making a new exception subclass that only supported the (string, exception) constructors so the end of your catch blocks was throw new OurException("method foo with params a="+a+" b="+b+" died", e); – more stack trace info, and each inner exception captured the params the method had been passed. That made things much easier to repro from production logs (some exceptions happened once a week under non-predictable scenarios). But I digress

    Anders once said (I forget where) that you really want a lot of try/finally blocks (ratio of 40:1 to try/catch blocks IIRC) – however, there’s a lot lost in finally blocks. Obviously is the "did we hit an exception or not?" data bit, which is why the developer still has the burden for flipping a boolean for whether to commit or not (as per Anders’ whiteboard session on using syntax for transaction boundaries). finally’s do have the benefit of not losing the "which exceptions can throw?" data bit, which is what catch (Exception e) {… throw; } does (AFAIK)

    What I really want is the ability to say "do this block if there’s an exception, but don’t actually catch the exception". try { whatever } on (Exception e) { log_some_info } – no catching, so the compiler has the same "who is throwing what?" data as if the try/on (or whatever word) block weren’t there at all. Conceptually, it’s an easy transition for developers that were doing catch blocks ending with throw; anyway. If they were throwing something other than the original exception, this doesn’t help them, of course, they still need to catch, but it does help the compiler. Of course, maybe the compiler recognizes catch with throw; and could still understand the exceptions possible, but a new syntax would be nice to help guide them to using throw; instead of throw e; or throw new whatever; since it’s only the throw; case that the compiler would still know the possible exceptions leaving the message AFAICT (well, it’d know either way, but we’re losing the granularity we would have had if there were no catch’s going on).

    An AOP-ish kind of approach also has potential benefits there (as others have noted) but I tend to agree with Anders on the front that you should be able to look at a chunk of code and be able to figure out the code paths (esp. exit paths) and splitting out exception handling makes for less understandable code w/o major IDE assistance (which Anders and I would agree shouldn’t become basically a language issue – if using C# means having to use VS, something’s gone wrong πŸ™‚

    Alright, enough babbling πŸ™‚

  13. This is horrible of me, and I shouldn’t even admit to it, but dang if most exception-handling stuff doesn’t get a lot simpler without much real utility loss if you just catch/throw Exception in most cases, and only pay attention to subtypes if you have specific reason to believe it matters.

  14. David Levine says:

    James,

    "What I really want is the ability to say "do this block if there’s an exception, but don’t actually catch the exception". try { whatever } on (Exception e) { log_some_info } – no catching, so the compiler has the same "who is throwing what?" data as if the try/on (or whatever word) block weren’t there at all. "

    As you state, you can rethrow the original exception, using throw; not throw e; There’s another option beside this that may be more what you are looking for.

    The CLR supports a fault block which provides almost exactly this functionality. It does not catch the exception and it only gets called if an exception has occurred. The fault block executes on the 2nd phase of the SEH mechanism, after all catch blocks have been examined to locate a handler and when finally and fault blocks run and the stack is getting unwound; it may not matter to you which phase it runs on but it’s something to be aware of.

    The bad news is that C# does not expose a syntax for this so you would have to write some IL to use this feature. Perhaps one day Cyrus will add support for this into C# πŸ™‚ It does seem like it would be useful for logging/instrumentation purposes.

  15. James, I also like your suggestion about "do this block if there’s an exception, but don’t actually catch the exception". I wish it will be added to C# one day.

    But now again about checked exceptions. I understand the above comments about why they aren’t an ideal solution. Also, as I understand, an ideal solution was not found yet. All ideas about code analyzis done by IDE and/or compiler are not intended to work in 100% cases and I even think that they cannot work in pretty large percent of cases. What is the solution for virtual calls problem? For example, we use interfaces pretty much and this makes me think that code analisys won’t help.

    On another side, checked exceptions at least provide you a choice. You can either carefully fill in exception specifications or just declare your exceptions unchecked (or add "throws Exception" to every method). In my experience, with good development tools (like IntelliJ or Eclise are for Java) checked exceptions are rather helpful than harmful. Why not providing this feature in C#/CLR?

  16. I know this doesn’t solve the whole problem, but I think it is a step in the right direction…

    John Robbins writes in MSDN Mag on how to create an FxCop rule that detects methods that throw exceptions, but do not have an accompanying <exception> documentation comment.

    http://msdn.microsoft.com/msdnmag/issues/04/09/Bugslayer/default.aspx

  17. Luke Stevens says:

    "Apart from anything else, genuinely recoverable exceptions seem to be extremely rare, and probably shouldn’t be reported as exceptions anyway, as they’re just not that exceptional."

    Amen. You should never have to care what the type of the exception is (isn’t switching on a type a cardinal sin of OO programming?), only whether one happened and what human-readable description to report when it is caught and swallowed. The only time you do have to care (but still shouldn’t have had to) is when you’re using a poorly designed component that uses exceptions inappropriately, e.g. a date parser that throws when a string is not a valid date without giving you a way to explicitly test for validity.

    If it were up to me, C# would not let you specify a type in a catch statement at all and would force you to explicitly cast from Exception (or Object?) to something else if you really mean to do that. And it would let you do so in a VB-style when clause. And of course it would also support try/fault.

  18. Luke Stevens says:

    Oh, and not that you would, but please don’t go through the documentation for every method in the framework and add a "this method might throw a ThreadAbortException", which is the logical conclusion of demanding to know what all exceptions can possibly occur.