I see people puzzled by this quite frequently, so I feel a discussion is in order.
This preference in the IDE does exactly as its name implies. Anytime an exception is throw by the debug application, the IDE will attempt to show you where the exception ocurred and what the exception is.
That's it.
So where does the confusion come in? It comes in because people are confused when it breaks on every exception, including ones that are handled, or cannot be displayed.
For instance, if you put this code into a method and run, you will break into the debugger:[rbcode]
try
raise new NilObjectException
catch err as NilObjectException
MsgBox "Caught you!"
end try[/rbcode]
Another example would be the AutoDiscovery class, which raises exceptions internally and handles them itself. (This actually happens at the EasyUDPSocket level, but no one seems to use that -- just AutoDiscovery).
In both cases, the debugger learns of the exception and breaks immediately. In the first case, there's source code to show you, so it breaks on the raise line. In the second case, there's no source code to show you (since it's an internal class) and so the debugger just reports that an exception has occurred (a KeyNotFoundException, to be accurate).
This is not a bug -- it's the behavior of the feature. But let's talk about why it works that way: because it must. Without that handy ESP module we've been trying to develop for years now, there's no way to break only on certain types of exceptions, but not others.
In order to break only on unhandled exceptions, the application would have to know at the moment the exception was raised that some code path will for sure be handling the exception. If it waits to find out, then it's too late because the execution point is no longer where it should be.
You might think that's it's easy or trivial to know if the exception is being handled, but that's a hugely expensive and difficult concept to tackle, which is ultimately futile.
This case is easy:[rbcode]
try
MsgBox someDictionary.Value( "The key that does not exist!" )
catch err as KeyNotFoundException
end try[/rbcode]
So is the more broad case:[rbcode]
try
MsgBox someDictionary.Value( "The key that does not exist!" )
catch
end try[/rbcode]
But what about this code:[rbcode]
Sub DoSomething()
MsgBox someDictionary.Value( "The key that does not exist!" )
End Sub[/rbcode]
How do you know that the caller doesn't handle the exception, like this:[rbcode]
try
DoSomething
catch
end try[/rbcode]
This process can continue up the call chain as well -- at any point, someone could be handling that very exception. It could be within the method which throws the exception, it could be 30 levels away. It's quite difficult to know at the moment the exception is raised whether the exception will be handled sometime in the future or not.
As I said before, this process is futile, and the astute may have already reasoned out why. On the Application class, there's a catch-all exception filter (App.UnhandledException). So that means *all* exceptions are handled at some point. So now we get into special-casing particular code paths. "This exception is handled if you see any exception handlers like this, but not any handlers like that." This complicates the process even more, and introduces a lot of possible places for bugs.
I think you now have a better understanding of why the Break on Exceptions feature works the way it does, which hopefully helps you determine when to use it and when not to. If you are handling a whole ton of exceptions in your code which are normal exceptions to handle, then you shouldn't have this preference turned on.
But you may be wondering "wait, what's the point to this feature and what should I use instead?" Well, keep in mind that many, many users don't know how to properly use the debugger -- they also don't properly understand exceptions either many times. So this feature really helps them out by showing them places they need to care. That's who the feature is aimed at. So how do you get notified when there are unhandled exceptions? Simple: put a Break call in the App.UnhandledException event. It will break into the debugger when an exception isn't handled. Then you can look at the RuntimeException's Stack property to get an idea of what method caused the exception and what the exception is. Is it as easy to use as Break on Exceptions? Depends on perspective and how often you use it.
ooo… i see a prime opportunity for a rblibrary article here: exceptions for n00bs.
To save confusion, it may be better to have a second option in the prefs: Break on unhandled exceptions. You and I know that we can have this functionality using the App.UnhandledException event, however many people don't.
It would mean the app would only break on critical issues, giving an otherwise identical experience to running a standalone app.
You're not the first to have that idea, David:
...You can raise exeption errors!? Sweet!
lol, oh yes -- that's been a nice feature of REALbasic since forever ago. Check out the raise keyword. You can also make your own custom exceptions by subclassing RuntimeException.
Hey, what happened to the link I had posted here? Did it get censored or is this blog deleting them? I'll try again: www.tempel.org/rb/exceptionhandling.html