When a method can throw an exception (i.e., its SIDL definition has a throws clause), a variable should be passed to hold an exception. For maximum backward compatibility, the exception argument type is a sidl.BaseInterface pointer that is assumed to implement the sidl.BaseException interface. The exception argument should appear after the return value when both occur in a method, and it behaves like an out parameter. After the call, the client should test this argument using is_null or not_null. If it is not_null, 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, and the best course of action is to ignore their values. If your code does not check the exception argument after each call that can throw an exception, any exceptions that are thrown will be utterly ignored; they will not propagate automatically to higher level routines.
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 90 code fragment to use this method.
use ExceptionTest_Fib use ExceptionTest_FibException use ExceptionTest_NegativeValueException use sidl_BaseInterface type(ExceptionTest_Fib_t) :: fib type(sidl_BaseInterface_t) :: except type(ExceptionTest_FibException_t) :: fibexcept type(ExceptionTest_NegativeValueException_t) :: nvexcept integer (selected_int_kind(9)) :: index, maxdepth, maxval, depth, result call new(fib) index = 4 maxdepth = 100 maxvalue = 32000 depth = 0 call getFib(fib, index, maxdepth, maxvalue, depth, result, except) if (not_null(except)) then call cast(except, fibexcept) if (not_null(fibexcept)) then ! do something here with the FibException else call cast(except, nvexcept) ! do something here with the NegativeValueException endif call deleteRef(except) else write (*,*) 'getFib for ', index, ' returned ', result endif call deleteRef(fib)
Here is an example of an implementation subroutine that throws an exception. Note you must cast the returned exception object into the exception out parameter. The setNote method provides a useful error message, and the add method helps provide a multi-language traceback capability (provided each layer of the call stack calls add).
recursive subroutine ExceptionTest_Fib_getFib_mi(self, n, max_depth, & max_value, depth, retval, exception) use sidl_BaseInterface use ExceptionTest_Fib use ExceptionTest_NegativeValueException use ExceptionTest_FibException use ExceptionTest_Fib_impl ! DO-NOT-DELETE splicer.begin(ExceptionTest.Fib.getFib.use) use ExceptionTest_TooBigException use ExceptionTest_TooDeepException ! DO-NOT-DELETE splicer.end(ExceptionTest.Fib.getFib.use) implicit none type(ExceptionTest_Fib_t) :: self integer (selected_int_kind(9)) :: n, max_depth, max_value integer (selected_int_kind(9)) :: retval, depth type(sidl_BaseInterface_t) :: exception ! DO-NOT-DELETE splicer.begin(ExceptionTest.Fib.getFib) type(ExceptionTest_NegativeValueException_t) :: negexc ! ...lines deleted... character (len=*) myfilename parameter(myfilename='ExceptionTest_Fib_Impl.f') retval = 0 if (n .lt. 0) then call new(negexc) if (not_null(negexc)) then call setNote(negexc, & 'called with negative n') call add(negexc, myfilename, 57, & 'ExceptionTest_Fib_getFib_impl') call cast(negexc, exception) return endif else ! ...numerous lines deleted.... ! DO-NOT-DELETE splicer.end(ExceptionTest.Fib.getFib) end subroutine ExceptionTest_Fib_getFib_mi
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 call set_null on 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.