Previous Up Next

Chapter 10  FORTRAN 77 Bindings


10.1  Introduction

This chapter provides an overview of the fortran 77 bindings for SIDL. Common aspects of the bindings, such as the mapping of SIDL data types to their native fortran 77 representatives, are presented in Section 10.2. Issues of concern to fortran 77 callers are addressed in the client-side bindings discussion in Section 10.3, while fortran 77 callees would benefit from a review of implementation-side issues in Section 10.4.

10.2  Basics

This section summarizes basic features that are common to both client and implementation bindings. Conventions used to protect the global name space are described in Subsection 10.2.1, while those associated with the generation of subroutines from methods are given in Subsection 10.2.2. Translations between SIDL and native fortran 77 constructs are described in Subsection 10.2.3. Finally, the process of casting between different types is illustrated in Subsection 10.2.4.

10.2.1  Name space

As with C bindings, the language does not have built-in mechanisms for protecting the global name space. As a result, fortran 77 bindings also attempt to avoid collisions by incorporating relevant naming information from the package and class. Since interfaces and classes map to INTEGER*8, there are no naming issues associated with these SIDL types. However, as discussed in Subsection 10.2.2, name space issues do arise for methods.

10.2.2  Method signatures

All SIDL methods are implemented as fortran 77 subroutines regardless of whether they have return values. The name of a subroutine used to call a SIDL method is a concatenation of the package, class (or interface), and method name, where each part is separated by an underscore. If the method is specified as overloaded (i. e., has a name extension), the extension is appended to the name part. An additional string is appended to further distinguish between client-side methods (to be invoked) and the implementation-side, where the former end in “_f” while the latter end in “_fi”.

As for arguments, the object (or interface) pointer is automatically inserted as the first parameter in the signature of non-static methods. This parameter operates like an in parameter. When a method has a return value, a variable to hold the return value should be passed as an argument following the formally declared arguments. This extra argument behaves like an out parameter. With the addition of remote method invocation (RMI) support, all methods now implicitly throw exceptions. Hence, an extra out parameter for the exception is automatically added at the end of the signature.

The following SIDL method — taken from regression tests — is an example of a method that can throw multiple exception types:

SIDL
int getFib(in int n, in int max_depth, in int max_value, in int depth) throws NegativeValueException, FibException;

The corresponding fortran 77 API is:

fortran 77
subroutine ExceptionTest_Fib_getFib_f(self, n, max_depth, & max_value, depth, retval, exception) implicit none C in ExceptionTest.Fib self integer*8 self C in int n integer*4 n C in int max_depth integer*4 max_depth C in int max_value integer*4 max_value C in int depth integer*4 depth C out int retval integer*4 retval C out sidl.BaseInterface exception integer*8 exception end

Note the addition of the object (i. e., self), return (i. e., retval), and exception (i. e., exception) parameters.

10.2.3  Data types


Table 10.1: SIDL to fortran 77 Type Mappings
SIDL TYPEfortran 77 TYPE
intINTEGER*4
longINTEGER*8
floatREAL
doubleDOUBLE PRECISION
boolLOGICAL
charCHARACTER*1
stringCHARACTER*(*)
fcomplexCOMPLEX
dcomplexDOUBLE COMPLEX
enumINTEGER
opaqueINTEGER*8
interfaceINTEGER*8
classINTEGER*8
arrayINTEGER*8

Basic SIDL types are mapped into fortran 77 according to Table 10.1. The remainder of this subsection elaborates on mappings of strings, pointers, enumerations, and arrays.

Strings

When mapping the SIDL string type into fortran 77, some capability was sacrificed to make it possible to use normal looking fortran 77 string handling. One difference is that all fortran 77 strings have a limited fixed size. Specifically, out string parameters are automatically limited to 512 characters each.

NOTE: Modification of the value of SIDL_F77_STR_MINSIZE in runtime/sidl/babel_config.h prior to configuring Babel can be used to change the string size limitation.

Pointers

Pointer types, such as opaque, interface, class, and array, translate into 64-bit integers to enable fortran 77 code portability between systems with 32-bit and 64-bit address spaces. On a 32-bit system, the upper 32 bits of these quantities are ignored. Systems with more than 64-bit pointers aren’t currently supported.

Generally, clients should treat opaque, interface, class, and array values as black boxes. However, there is one value that is special. A value of zero for any of these quantities indicates the pointer does not refer to an object, thus making zero the fortran 77 equivalent of NULL. Any nonzero value is or should be a valid object reference. Developers should initialize values to be passed as in or inout parameters to zero or a valid object reference.

Enumerations

SIDL enumerations map to integer values. For compilers that support some form of inclusion, constants are defined in an inclusion file. Specifically, Babel will generate fortran 77 include files in the style of DEC FORTRAN (Compaq FORTRAN? (now HP FORTRAN???)) %INCLUDE. These files are named by taking the fully qualified name of the enum, changing the periods to underscores, and appending .inc.

Given the specification of a car enumeration type from Section 6.3, the corresponding include file is:

fortran 77
C File: enums_car.inc C Symbol: enums.car-v1.0 C Symbol Type: enumeration C Babel Version: 0.5.0 C Description: Automatically generated; changes will be lost C C babel-version = 0.5.0 C source-line = 25 C integer porsche parameter (porsche = 911) integer ford parameter (ford = 150) integer mercedes parameter (mercedes = 550)

The following snippet illustrates the inclusion of the file and an assignment of the mercedes constant:

fortran 77
integer*4 myCar C include the enumeration constants file include 'enums_car.inc' myCar = mercedes

Arrays

As discussed in Section 6.4, SIDL supports both normal and raw arrays (i. e., r-arrays). Normal SIDL arrays can be used by any supported language; whereas, r-arrays are restricted to numeric types and use in languages such as C, C++, and Fortran. This subsection discusses both within the context of fortran 77 bindings. More information on the FORTRAN 77 version of the SIDL array API can be found in Subsection 6.4.

The difference in how normal SIDL arrays and r-arrays are accessed is profound. A normal SIDL array is passed as an integer*8, and accessed using an API or by converting the array data to an index into a known array. R-arrays appear like normal fortran 77 arrays, so there is a big incentive to use r-arrays for performance purposes, when appropriate.

The client-side interface for the solve example introduced in Section 6.4 behaves as if it is a fortran 77 function with the following declarations:

fortran 77
subroutine num_Linsol_solve_f(self, A, x, m, n, exception) implicit none C in num.Linsol self integer*8 self C in int m, n integer*4 m, n C out sidl.BaseInterface exception integer*8 exception C in rarray<double,2> A(m,n) double precision A(0:m-1, 0:n-1) C inout rarray<double> x(n) double precision x(0:n-1) end

NOTE: Array indices go from 0 to m−1 instead of the normal 1 to m. This was a concession to the C/C++ programmers who have to deal with the fact that A is stored in column-major order.

The remainder of this section is dedicated to describing how normal SIDL arrays are accessed. The normal SIDL C function API is available to create, destroy, and access array elements and meta-data — with _f appended to subroutine names but no extra exception arguments.

For dcomplex, double, fcomplex, float, int, and long SIDL types, a method is provided to get direct access to array elements. For other types, you must use the array API to access elements. For SIDL type X, a fortran 77 function called sidl_X__array_access_f provides direct access, as illustrated below. This will not work if your fortran 77 compiler does array bounds checking, however.

fortran 77
integer*4 lower(1), upper(1), stride(1), i, index(1) integer*4 value, refarray(1), modval integer*8 nextprime, refindex, tmp lower(1) = 0 value = 0 upper(1) = len - 1 call sidl_int__array_create_f(1, lower, upper, retval) call sidl_int__array_access_f(retval, refarray, lower, $ upper, stride, refindex) do i = 0, len - 1 tmp = value value = nextprime(tmp) modval = mod(i, 3) if (modval .eq. 0) then call sidl_int__array_set1_f(retval, i, value) else if (modval .eq. 1) then index(1) = i call sidl_int__array_set_f(retval, index, value) else C this is equivalent to the sidl_int__array_set_f(retval, index, value) refarray(refindex + stride(1)*(i - lower(1))) = $ value endif endif enddo

To access a two-dimensional array, the expression referring to element i, j is:

fortran 77
refarray(refindex + stride(1) * (i - lower(1)) + stride(2) * $ (j - lower(2))

The expression referring to element i, j, k of a three-dimensional array is:

fortran 77
refarray(refindex + stride(1) * (i - lower(1)) + stride(2) * $ (j - lower(2)) + stride(3) * (k - lower(3))

Software packages such as LINPACK or BLAS can be called, but the stride should be checked to make sure the array is suitably packed. stride(i) indicates the distance between elements in dimension i, where a value of 1 means elements are packed densely in dimension i. Negative stride values are possible and, when an array is a slice of another array, there may be no dimension with a stride of 1.

NOTE: For a dcomplex array, the reference array should be a Fortran array of REAL*8 instead of a Fortran array of double complex to avoid potential alignment problems. For a fcomplex array, the reference array is a COMPLEX*8 because we don’t anticipate an alignment problem in this case.

10.2.4  Type casting

Babel automatically generates two methods for casting between interfaces and classes: _cast() and _cast2(). The _cast() method, which tries to convert its opaque argument to the type of the class indicated by the method name, is static. Similarly, the non-static _cast2() method attempts to convert an object pointer to the named type — specified as a string. For example, the following code snippet creates an instance of sidl.BaseClass then casts it to sidl.BaseInterface using each of the two methods:

fortran 77
integer*8 object, interface, except call sidl_BaseClass__create_f(object, except) call sidl_BaseInterface__cast_f(object, interface, except) c the following call to _cast2 is equivalent to the previous _cast call call sidl_BaseClass__cast2_f(object, 'sidl.BaseInterface', $ interface, except)

In either case, a zero except means the cast was successful and the returned reference (i. e., interface) should be non-zero. Since Babel 0.11.0, both methods increment the reference count when they are able to successfully cast the object. The caller then owns the returned reference.

10.3  Client-side

This section summarizes aspects of generating and using the fortran 77 bindings associated with software wrapped with Babel’s language interoperability middleware. The bindings generation process is presented before summarizing object management and invocation of static and overloaded methods. The process of catching exceptions is then discussed. Finally, the processes for enabling and disabling implementation-specific pre- and post-method instrumentation — referred to as “hooks” — are illustrated.

10.3.1  Bindings generation

The basic command line for creating the fortran 77 stubs for a SIDL file (called “file.sidl”) is 1:

% babel --exclude-external --client=f77 file.sidl

or simply

% babel -E -c=f77 file.sidl

The command results in the creation of a makefile fragment, called babel.make, numerous C header and source files, and some FORTRAN 77 files. Files ending in _fStub.c are the fortran 77 stubs that allow fortran 77 to call a SIDL method. These files (i. e. those listed in STUBSRCS in babel.make), need to be compiled and linked into the application.

Normally, IOR files (i. e., those ending in _IOR.c) are linked together with the implementation file, so do not need to be compiled. Files with the .fif extension are documentation for fortran 77 programmers showing how the class and interface would have been defined if they were implemented in FORTRAN 77. Consequently, .fif files are only for reference, so should not be compiled.

10.3.2  Object management

SIDL-specified objects are managed through explicit creation and reference counting. Babel automatically generates an _create method for concrete classes. The method is used to instantiate the class and return the associated reference. The owner of the instance is responsible for its proper disposal. In other words, when processing with the object is done, the owner must invoke deleteRef on it. Similarly, any object references returned by a subroutine call must be deleted or given to another part of the code that will take ownership of and, therefore, responsibility for deleteRef’ing it.

For example, the following calls deleteRef() using the sidl.BaseInterface version of the method:

fortran 77
integer*8 interface1, except C code to initialize interface1 here call sidl_BaseInterface_deleteRef_f(interface1, except)

When it is necessary to determine if two references point to the same object, the built-in isSame method can be used. For example, the following attempts to determine if interface1 and interface2 point to the same object:

fortran 77
integer*8 interface1, interface2, except logical areSame C code to initialize interface1 and interface2 here call sidl_BaseInterface_isSame_f(interface1, $ interface2, areSame, except) C now areSame holds the return value

Similarly, it is sometimes necessary to find out if a given method is of a specific type. One case in point is when trying to determine if an exception is of a given type. The built-in isType method is provided for that purpose. For example, the following tries to determin if interface1 is of type x.y.z:

fortran 77
integer*8 interface1, except logical typeMatch C code to initialize interface1 here call sidl_BaseInterface_isType_f(interface1, 'x.y.z', $ typeMatch, except)

Along those same lines, it is possible to find the name of a SIDL class that implements a particular interface. Using a sequence of calls with sidl.BaseInterface interface, this can be accomplished as follows:

fortran 77
integer*8 interface1, classinfo, except character*256 className C code to initialize interface1 here call sidl_BaseInterface_getClassInfo_f(interface1, $ classinfo, except) call sidl_ClassInfo_getName_f(classinfo, className, except) call sidl_BaseInterface_deleteRef_f(classinfo, except)

10.3.3  Static methods

Below is an example illustrating a call to addSearchPath(), which is a static method in the sidl.Loader class.

fortran 77
integer*8 except call sidl_Loader_addSearchPath_f('/try/looking/here', except)

Note the function is invoked directly, without an object reference argument.

10.3.4  Overloaded methods

Examples of calls to SIDL overloaded methods are based on the overload_sample.sidl file shown in Section 6.7. Recall that the file describes three versions of the getValue method. The first takes no arguments, the second takes an integer, and the third a boolean. Each is called in the code snippet below:

fortran 77
integer*8 t, except logical b1, bretval integer*4 i1, iretval call Overload_Sample__create_f (t, except) call Overload_Sample_getValue_f (t, iretval, except) call Overload_Sample_getValueInt_f (t, i1, iretval, except) call Overload_Sample_getValueBool_f (t, b1, bretval, except)

10.3.5  Exception catching

Since all methods can now throw sidl.RuntimeException , Babel ensures there is an out argument to hold an exception. If not explicitly specified, Babel will automatically add the argument. For maximum backward compatibility, the base exception argument type is sidl.BaseInterface, while 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 caller should respond appropriately. When an exception is thrown, the value of all other arguments is undefined (so should be ignored).

One approach to exception handling is to pass the exception on to the caller. In this case, sidl.BaseException.add should be called to add another line in the stack trace for the exception. 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 called function, so it can be empty. Similarly, getTrace provides a summary of the call stack. Again, implementors are responsible for providing the information.

Alternatively, the caller could try to determine which exception was thrown through casting the argument. A successful cast indicates the type of exception that has occurred. An example of this process is illustrated below, though not all exceptions associated with the method are checked. The SIDL specification and corresponding fortran 77 API are given in Section 10.2.2.

fortran 77
integer*8 fib, except, except2, except3 integer*4 index, maxdepth, maxval, depth, result call ExceptionTest_Fib__create_f(fib, except) if (except .ne. 0) then 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)

If one of the possible exception types is a subclass of another, casting to the subclass should be attempted before casting to the superclass — assuming that the distinction between the two exception types results in different exception recovery behavior.

10.3.6  Hooks execution

If a given component supports pre- and post-method invocation instrumentation, also known as “hooks”, their execution can be enabled or disabled at runtime through the built-in _set_hooks method. For example, given the following SIDL specification:

SIDL
package hooks version 1.0 { class Basics { /** * Basic illustration of hooks for static methods. */ static int aStaticMeth(in int i, out int o, inout int io); /** * Basic illustration of hooks for static methods. */ int aNonStaticMeth(in int i, out int o, inout int io); } }

which has a single static function and a member function for the Basics class, the processes for enabling and disabling execution of the implementation-specific hooks are:

fortran 77
integer*8 obj, except call hooks_Basics__create_f (obj, except) c c Enable hooks execution (enabled by default) c ...for static methods c call hooks_Basics__set_hooks_static_f (1, except) c c ...for non-static methods c call hooks_Basics__set_hooks_f (obj, 1, except) c c ...do something meaningful... c c c Disable hooks execution c ...for static methods c call hooks_Basics__set_hooks_static_f (0, except) c c ...for non-static methods c call hooks_Basics__set_hooks_f (obj, 0, except) c c ...do something meaningful... c

It is important to keep in mind that the _set_hooks_static method must be used to enable/disable invocation of hooks for static methods and the _set_hooks method must be used for those of non-static methods. Also, Babel does not provide client access to the _pre and _post methods; therefore, they cannot be invoked directly. More information on the instrumentation process is provided in Subsection 10.4.5.

10.3.7  Contract enforcement

Interface contracts specify the expected behaviors of callers (or clients) and callees (or servers) of methods defined for interfaces and classes. Once specified, contracts are optionally enforced at runtime, through checks automatically integrated into the middleware generated by the Babel compiler. This section provides an example of a specification and code snippets for performing basic, traditional contract enforcement — introduced in Section 6.5 — in a fortran 77 client.

A SIDL specification, including preconditions and postconditions, for calculating the sum of two vectors is given below. (Refer to Section 6.5 for an introduction to the contract syntax.) According to the preconditions, all callers are expected to provide two one-dimensional, SIDL arrays of the same size as arguments. The postconditions specify that all implementations are expected to return a non-null, one-dimensional array of the same size (as the first SIDL array), assuming the preconditions are satisfied.

SIDL
package vect version 1.0 { class Utils { /* ... */ /** * Return the sum of the specified vectors. */ static array<double> vuSum(in array<double> u, in array<double> v) throws sidl.PreViolation, sidl.PostViolation; require not_null_u: u != null; u_is_1d : dimen(u) == 1; not_null_v: v != null; v_is_1d : dimen(v) == 1; same_size: size(u) == size(v); ensure no_side_effects : is pure; result_not_null: result != null; result_is_1d : dimen(result) == 1; result_correct_size: size(result) == size(u); } /* ... */ }

An example of a fortran 77 client invoking the method is given below. The code snippet illustrates declaring and creating the arrays; enabling full contract enforcement (i. e., checking all contract clauses); executing vuSum; handling contract violation exceptions; and cleaning up references is given below.

fortran 77
integer*8 exc, tae integer*8 u, v, x include 'sidl_ContractClass.inc' call createDouble(MAX_SIZE, u) call createDouble(MAX_SIZE, v) C Initialize u and v. C Enable FULL contract enforcement. call sidl_EnfPolicy_setEnforceAll_f(ALLCLASSES, .true., $ exc) if (exc .ne. 0) then C Handle the exception endif C Do something meaningful before executing the method. call vect_Utils_vuSum_f(u, v, x, exc) if (exc .ne. 0) then C Handle the exception endif C Do something meaningful with the result, x. call sidl_double__array_deleteRef_f(u, tae) call sidl_double__array_deleteRef_f(v, tae) if (x .ne. 0) then call sidl_double__array_deleteRef_f(x, tae) endif end

Alternative enforcement options can be set, as described in Section 6.5, through the two basic helper methods: setEnforceAll and setEnforceNone. The code snippet below shows the fortran 77 calls associated with the traditional options of enabling only precondition enforcement, enabling postcondition enforcement, or completely disabling contract enforcement.

fortran 77
include 'sidl_ContractClass.inc' C C Enable only precondition contract enforcement. C (Useful when only need to ensure callers comply with contract.) C call sidl_EnfPolicy_setEnforceAll_f(PRECONDS, .false., exception) if (exception .ne. 0) C Handle the exception endif C C Enable only postcondition contract enforcement. C (Useful when only need to ensure implementation(s) comply with contract.) C call sidl_EnfPolicy_setEnforceAll_f(POSTCONDS, .false., exception) if (exception .ne. 0) C Handle the exception endif C C Disable contract enforcement. C (Should only be used when have confidence in caller AND implementation.) C call sidl_EnfPolicy_setEnforceNone_f(.false., exception) if (exception .ne. 0) C Handle the exception endif

This section illustrates the basic interfaces and processes for traditional interface contract enforcement for a fortran 77 client. Additional enforcement policy options and methods as well as more information regarding the specification and enforcement of contracts can be found in Chapter 21.

10.4  Implementation-side

This section summarizes aspects of generating and wrapping software written in fortran 77. The bindings generation and basic implementation processes are presented first. Since access to object state requires special steps in fortran 77, the process for defining and managing that data is discussed. Throwing exceptions in the implementation is then illustrated. Finally, the results of generating implementations with pre- and post-method “hooks” are shown.

10.4.1  Bindings generation

Much of the information associated with generating client-side bindings is pertinent to implementing a SIDL class in fortran 77. (Recall Table 10.1 listed the type mappings.) If the implementation calls other SIDL methods, client-side caller rules must be followed.

Implementation-side bindings are generated by the following call to Babel:

% babel --exclude-external --server=f77 file.sidl

or simply

% babel -E -s=f77 file.sidl

As a result, a makefile fragment called babel.make, numerous C header and source files, and some fortran 77 source files are created. Implementation details must be added to the fortran 77 “Impl” files, whose names end with _Impl.f. More on this matter is provided in Subsection 10.4.2.

10.4.2  Bindings implementation

Implementation details must be added to the “Impl” files generated in Subsection 10.4.1. Changes to these files must be made between code splicer pairs to ensure their retention in subsequent invocations of Babel. Below is an example of a code splicer pair.

fortran 77
C DO-NOT-DELETE splicer.begin(_miscellaneous_code_start) C Insert-Code-Here {_miscellaneous_code_start} (extra code) C DO-NOT-DELETE splicer.end(_miscellaneous_code_start)

where the “C Insert-Code-Here...” line should be replaced with the implementation. Examples of filling in these splicer blocks are provided in the subsections to follow.

10.4.3  Private data

Any variables declared in the implementation source file will, by virtue of Babel’s encapsulation, be private. Special initialization procedures can be added to the built-in _load() method that is guaranteed to be called exactly once per class to set global class data — before any user-defined methods can even be invoked. Alternatively, if private data (sometimes referred to as state) needs to be added to a fortran 77 class, SIDL arrays can be used to store the data. This is certainly not the only way to implement a fortran 77 class with state, but it’s one that will work wherever Babel works.

The SIDL IOR keeps a pointer (i. e., a C void *) for each object in order to support private data. Like their C equivalents, each fortran 77 skeleton provides two functions for accessing the private pointer. Although the pointer arguments to the methods are 64-bit integers in fortran 77, the number of bits actually stored by the IOR is determined by sizeof(void *). Babel/SIDL does not provide a low level mechanism for fortran 77 to allocate memory to use for the private data pointer.

The following example illustrates the process of managing private data using the automatically generated constructor subroutine, _ctor:

fortran 77
subroutine example_withState__ctor_fi(self, exception) implicit none integer*8 self, exception C DO-NOT-DELETE splicer.begin(example.withState._ctor) integer*8 statearray, logarray, dblarray call sidl_opaque__array_create1d_f(2, statearray) call sidl_bool__array_create1d_f(3, logarray) call sidl_double__array_create1d_f(2, dblarray) if ((statearray .ne. 0) .and. (logarray .ne. 0) .and. $ (dblarray .ne. 0)) then call sidl_opaque__array_set1_f(statearray, 0, logarray) call sidl_opaque__array_set1_f(statearray, 1, dblarray) else C a real implementation would not leak memory like this one statearray = 0 endif call example_withState__set_data_f(self, statearray) C DO-NOT-DELETE splicer.end(example.withState._ctor) end

Of course, it is up to the implementation to associate elements of the arrays with particular state variables. For example, element 0 of the double array could be the kinematic viscosity and element 1 the airspeed velocity of an unladen swallow. Element 0 of the boolean array could specify African (true) or European (false). The destructor implementation for this class could look something like:

fortran 77
subroutine example_withState__dtor_fi(self, exception) implicit none integer*8 self, exception C DO-NOT-DELETE splicer.begin(example.withState._dtor) integer*8 statearray, logarray, dblarray call example_withState__get_data_f(self, statearray) if (statearray .ne. 0) then call sidl_opaque__array_get1_f(statearray, 0, logarray) call sidl_opaque__array_get1_f(statearray, 1, dblarray) call sidl_bool__array_deleteRef_f(logarray) call sidl_double__array_deleteRef_f(dblarray) call sidl_opaque__array_deleteRef_f(statearray) C the following two lines are not strictly necessary statearray = 0 call example_withState__set_data_f(self, statearray) endif C DO-NOT-DELETE splicer.end(example.withState._dtor) end

Continuing with this example, an accessor function for the airspeed velocity of an unladen swallow could be implemented as follows:

fortran 77
subroutine example_withState_getAirspeedVelocity_fi( $ self, velocity, exception) implicit none integer*8 self, exception real*8 velocity C DO-NOT-DELETE splicer.begin(example.withState.getAirspeedVelocity) integer*8 statearray, dblarray call example_withState__get_data_f(self, statearray) if (statearray .ne. 0) then call sidl_opaque__array_get1_f(statearray, 1, dblarray) call sidl_double__array_get1_f(dblarray, 1, velocity) endif C DO-NOT-DELETE splicer.end(example.withState.getAirspeedVelocity) end

10.4.4  Exception throwing

Continuing with the Fibonocci example used in Subsections 10.2.2 and 10.3.5, the fortran 77 code that throws the exceptions is:

fortran 77
subroutine ExceptionTest_Fib_getFib_fi(self, n, max_depth, & max_value, depth, retval, exception) implicit none integer*8 self, exception, ignored 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 $ ,ignored) if (exception .ne. 0) then call ExceptionTest_NegativeValueException_setNote_f( $ exception, $ 'called with negative n', ignored) call ExceptionTest_NegativeValueException_add_f( $ exception, $ myfilename, $ 57, $ 'ExceptionTest_Fib_getFib_impl', ignored) return endif C ...lines of code deleted... C DO-NOT-DELETE splicer.end(ExceptionTest.Fib.getFib) end

Not all exceptions are thrown in this example in order to keep its length down. The interested reader is encouraged to refer to the corresponding regression tests for the complete routine.

When an exception is thrown, the implementation should deleteRef any references it was planning to return to the caller because the caller is instructed to ignore any returned values under those circumstances. In general, when throwing an exception, it is good practice to set all out and inout array, class, and interface arguments to zero before returning. This makes things work out better for clients who forget to check if an exception occurred or willfully choose to ignore it.

NOTE: It is typically 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.

10.4.5  Hooks implementation

As discussed in Subsection 10.3.6, when hooks execution is enabled, implementation-specific instrumentation is executed. Using the --generate-hooks option on the Babel command line when generating implementation-side bindings results in the automatic generation of a _pre and _post method for every static and non-static method associated with each class in the specification. For the aStaticMethod specified in Subsection 10.3.6, the generated _pre method implementation is:

fortran 77
subroutine hooks_Basics_aStaticMeth_pre_fi(i, io, exception) implicit none C in int i integer*4 i C in int io integer*4 io C out sidl.BaseInterface exception integer*8 exception C DO-NOT-DELETE splicer.begin(hooks.Basics.aStaticMeth_pre) C C Add instrumentation here to be executed immediately prior C to dispatch to aStaticMeth(). C C DO-NOT-DELETE splicer.end(hooks.Basics.aStaticMeth_pre) end

while that of the _post method is:

fortran 77
subroutine hooks_Basics_aStaticMeth_post_fi(i, o, io, retval, & exception) implicit none C in int i integer*4 i C in int o integer*4 o C in int io integer*4 io C in int retval integer*4 retval C out sidl.BaseInterface exception integer*8 exception C DO-NOT-DELETE splicer.begin(hooks.Basics.aStaticMeth_post) C C Add instrumentation here to be executed immediately after C return from dispatch to aStaticMeth(). C return C DO-NOT-DELETE splicer.end(hooks.Basics.aStaticMeth_post) end

Per the normal implementation process, the desired instrumentation should be added within the splicer blocks of aStaticMethod_pre and aStaticMethod_post. As stated in the comments within those blocks, aStaticMethod_pre will be executed immediately prior to dispatch to aStaticMethod when the latter is invoked by a client. Assuming no exceptions are encountered, aStaticMethod_post is executed immediately upon return from aStaticMethod.


1
For information on additional command line options, refer to Section 4.2.

Previous Up Next