next up previous contents index
Next: Invoking Babel to generate Up: FORTRAN 77 Bindings Previous: Calling Methods From FORTRAN   Contents   Index


Catching and Throwing Exceptions in FORTRAN 77

All SIDL methods can throw an exception; hence, an extra variable of type INTEGER*8 must be passed to hold a pointer if an exception is thrown. All methods implicitly throw sidl.RuntimeException even if the SIDL declaration does not have a throws clause. The sidl.RuntimeException is used primarily to indicate that an error occurred in the Babel generated code or that a network failure occurred for distributed Babel calls.

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 should 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, except3
       integer*4 index, maxdepth, maxval, depth, result
       call ExceptionTest_Fib__create_f(fib, except)
       if (except .ne. 0) thn
C         do something with a runtime exception
       endif
       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, except3)
         if (except2 .ne. 0) then
c           do something here with the FibException
            call ExceptionTest_FibException_deleteRef_f(except2, except3)
         else
           call ExceptionTest_NegativeValueException__cast_f
     $           (exception, except2, except3)
c          do something here with the NegativeValueException
            call ExceptionTest_NegativeValueException_
     $           deleteRef_f(except2, except3)
         endif
         call sidl_BaseException_deleteRef_f(except, except3)
       else
         write (*,*) 'getFib for ', index, ' returned ', result
       endif
       call ExceptionTest_Fib_deleteRef_f(fib, except)

Here is an example of FORTRAN 77 code that throws an exception. Note that not all exceptions are checked in this example. In general, it is safe to assume that calling deleteRef, _cast or _cast2 on an exception will never cause an exception to be thrown because returned exceptions are always local.


        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 because the caller is instructed to ignore any values returned when an exception is thrown. 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 to zero 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.


next up previous contents index
Next: Invoking Babel to generate Up: FORTRAN 77 Bindings Previous: Calling Methods From FORTRAN   Contents   Index


babel-0.99.0
users_guide Last Modified 2006-06-27

http://www.llnl.gov/CASC/components
components@llnl.gov