When a method can throw an exception (i.e., its SIDL definition has a throws clause), an extra variable of type INTEGER*8 should be passed to hold a pointer if an exception is thrown. For maximum backward compatibility, the base exception type argument is sidl.BaseInterface though the base exception class is sidl.SIDLException. The exception argument appears after the return value when both occur in a method. After the call, the client must test this argument. If a function does not test the exception argument, thrown exceptions will be utterly ignored -- not propagated to higher level functions. If the exception parameter is non-zero, an exception was thrown by the method, and the method should respond appropriately. When an exception is thrown, the value of all other arguments is undefined.
When the exception parameter is non-zero, your code should try casting it to each of the possible exceptions in turn. A successful cast indicates the type of exception that has occured. If one of the possible exception types is a subclass of another one, you should try casting to the subclass before casting to the super class -- assuming that the distinction between the two exception types results in different exception recovery behavior.
sidl.BaseException defines two methods that can be helpful when reporting exceptions to end users: getNote and getTrace. getNote often provides some indication of what went wrong. Its contents are provided by the implementor of the function you called, so it can be empty. Similarly, getTrace make provide a summary of the call stack. Again, it depends on implementors to provide information.
One approach to exception handling is to pass the exception on to your caller. In this case, you should call sidl.BaseException.add to add another line in the stack trace for the exception.
Here is another example adapted from the Babel regression tests. Package ExceptionTest has a class named Fib with a method declared in SIDL as follows:
int getFib(in int n, in int max_depth, in int max_value, in int depth) throws NegativeValueException, FibException;
Here is the outline of a FORTRAN 77 code fragment to use this method. When an exception is thrown, the value of the out and inout parameters is unknown, the best practice is to ignore their values.
integer*8 fib, except, except2 integer*4 index, maxdepth, maxval, depth, result call ExceptionTest_Fib__create_f(fib) index = 4 maxdepth = 100 maxvalue = 32000 depth = 0 call ExceptionTest_getFib_f(fib, index, maxdepth, $ maxvalue, depth, result, except) if (except .ne. 0) then call ExceptionTest_FibException__cast_f(except, except2) if (except2 .ne. 0) then c do something here with the FibException else call ExceptionTest_NegativeValueException__cast_f $ (exception, except2) c do something here with the NegativeValueException endif call sidl_BaseException_deleteRef_f(except) else write (*,*) 'getFib for ', index, ' returned ', result endif call ExceptionTest_Fib_deleteRef_f(fib)
Here is an example of FORTRAN 77 code that throws an exception.
subroutine ExceptionTest_Fib_getFib_fi(self, n, max_depth, & max_value, depth, retval, exception) implicit none integer*8 self, exception integer*4 n, max_depth, max_value, depth, retval C DO-NOT-DELETE splicer.begin(ExceptionTest.Fib.getFib) character*(*) myfilename parameter(myfilename='ExceptionTest_Fib_Impl.f') C ...lines of code deleted... if (n .lt. 0) then call ExceptionTest_NegativeValueException__create_f(exception) if (exception .ne. 0) then call ExceptionTest_NegativeValueException_setNote_f( $ exception, $ 'called with negative n') call ExceptionTest_NegativeValueException_add_f( $ exception, $ myfilename, $ 57, $ 'ExceptionTest_Fib_getFib_impl') return endif C ...lines of code deleted... C DO-NOT-DELETE splicer.end(ExceptionTest.Fib.getFib) end
Please note that when your code throws an exception it should deleteRef any references it was planning to return to its caller. Any caller of a method that returns an exception should ignore the values of out and inout parameters, so anything you do not free will become a reference and memory leak. In general, it is good practice to set all out and inout array, class and interface arguments before returning when throwing an exception. This makes things work out better for clients who forget to check if an exception occurred or willfully choose to ignore it.