Wednesday, April 15, 2009

Suneido Exception Handling

One annoying part of exceptions in Suneido is that there's no way to "properly" re-throw an exception.

You can catch (e.g. to perform some cleanup or logging), and then re-throw but then the debugger shows the source of the error as being your re-throw, not the original. This makes it hard to figure out the original source of the problem.

This was an area that caused me some confusion moving from C++ to Java. In C++ you re-throw by saying just "throw;" without any exception value. Java doesn't have this. At first, I thought that meant you couldn't re-throw in Java, but you can.

I had also wondered why Java code always constructed new exception objects to throw. Why not just have some static exception objects you could re-use?

The reason is that it is the exception constructor that captures information about the location of the error, and the call stack, etc. So obviously, re-using exception objects wouldn't work too well!

So to re-throw in Java, you simply throw the exception you caught. It will have the correct information since it was constructed at the site of the original error. (Unless you want to disregard that information, in which case you can always just construct a new exception.)

It seemed like this approach might be a possible way to improve Suneido's exception handling. But Suneido exceptions are thrown and caught as strings, not exception objects, which makes it a little tougher to include exception information.

But it should be feasible. The value given to catch could be an object that inherits from SuString, but adds exception information. throw could allow either a simple string, in which case you'd construct an exception string with information about the current call stack. Or you could re-throw an exception string from catch, in which case you'd preserve the original information.

And the string-like exception object could also have methods for getting the call stack information, which would be useful for things like logging.

Actually, cSuneido already does part of this. Internally, a throw creates an exception object that records the current frame and stack pointers. But catch is only given the thrown string part of the exception. And it's only recording pointers, so if any code runs (e.g. exception handling code) then the call stack is lost (overwritten).

To preserve the information, you'd have to actually copy it before it was overwritten. Currently, that's only done for uncaught exceptions which end up in the debugger. To allow catch and re-throw you'd have to copy the information before you executed any exception handling code, which would probably be simplest to do at the throw. This could slow down exception handling, but exceptions shouldn't be getting used anywhere that would be a problem. (Note: On Java with jSuneido the Java exception object already captures the information for us.)

Currently, Suneido doesn't have support for "finally" like Java. I thought it would be easy to add this to jSuneido since Java supports it. But unfortunately, finally is implemented by the Java compiler, rather than the JVM. TANSTAAFL


Jen said...

So does that mean that book pages wrapped in Curry would actually tell you where the error is occurring with JSuneido? 'Cause that would be really sweet!

andrew said...

This is for the current cSuneido.

As long as the problem is that the exception is being caught and re-thrown, then it should solve it.