A topic any developer worth his/her salt should know, but nonetheless…

A while back I ran into an issue with trying to trace propagated errors. While there’s numerous examples of global error handlers, pushing and popping call stacks to arrays and even “above and beyond” solutions like Wayne Phillips’ vbWatchDog utility, none of them provided a “natural” means to handle error tracing under the specific scenario of determining what code raised an error when the source of the error was a procedure whose errors were propagated to the caller.

To lay out the scenario a bit more: I tend to make use of propagating errors in certain circumstances, primarily within class objects where I want to handle the failure within the initiated procedure instead of having to programmatically track back through a mess of function calls by way of return values indicating completion status for each procedure. That’s a bit of a mess.

Typically, we’ll use the Erl() line function to determine what line the error was raised on (because of course, we all add line numbers to the project as part of the distribution process, right?). The problem with Erl() is that it doesn’t quite return the line that the error was thrown on… it returns the line in the procedure where the error is first handled. Consider the following:

Running the above sample code, you can see that the Error Line reported by Erl() is 4. Technically, in my eyes at least, this is incorrect. Or maybe it’s “correct” but just doesn’t meet my needs.

The reason this is returned as 4 is because line 4 is the first line within a handled block of code that receives the error.

Now, when I’m umpteen nested calls of code deep into some complex object logic, having the error propagate to the calling procedure is extremely handy. As mentioned, the other option is to write every single procedure to return a status, and every single caller to check that status and return its own status to its caller, etc. Stuff like this:

This coding structure is ugly… besides the fact that it’s entirely not semantic, we end up doing all sorts of stuff to get our values passed around as required (often times, giving double meaning to return values: if < 0 then SomeError). I’ve seen worse coding nightmares, but this is pretty bad. Not something that’ll find it’s way into my projects.

“I have to get information on where this error actually ocurred, but I refuse to write this insanely complex class with nasty code to return status indicators for all of its procedures… how can I do this???”
The answer took a bit to come up with, and a fair amount of trial and error, but once I had it down? … it’s beautiful.

Write a global error handler that has the usual niceties of a global handler: custom messaging, logging, etc. Additionally, have it optionally re-raise the error in a manner where the error will be propagated to the caller. Couple that with a “silence” option within the handler, and what you have is exactly what’s required for complex nested propagated errors: perfect propagation behavior with true “at error” time logging.

Here it is:

As simple as it seems, the trick is in the If Rethrow Then block. That’s what sends the original error back to the caller, which in turn gets thrown back once more, where we then run the process again until we have a “handled” error.

Usage is stupid simple, which is the second reason why I love it so much. Here’s my MZ-Tools handler – one word does it for “standard” errors:

And then, to propagate it and send it to the caller, just add three commas and two trues:

And that, my friends, is some awesome functionality out of a small handful of code lines.

Cheers!
-jack