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.
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.