IDL

IDL is the Interface Definition Language, whose syntax is defined as part of the CORBA(Common Object Request Broker) standard. Dave Quarrie of LBL has modifed the IDL compiler to generate interface code from C++ or Fortran 90. David has supplied most of the commentary below. For BaBar, the interface to Farfalla is described in an IDL input file. The colias.idl file describes the existing BaBar data model. It cheats a bit since F_Node should be in module farfalla instead of colias, but my code generator expects that for module, class there is a .hh file of the form "module/class.hh", and that doesn't exist within farfalla for F_Node. It was just easier for me to add the relevant .hh file to colias.

The compiler then generates

a rather large Fortran 90 interface

90% of the F-90 code is interface declarations - i.e. no real machine code is generated. All it does is to allow type checking etc. and tell the F-90 client what the C glue is actually going to do. The 10% that is actually code is routines to copy data (attributes in the IDL terminology) between a F-90 structure and a C++ object (and v.v.) for each interface, and routines to perform typecasting for F-90 structures (F-90 doesn't have a way of typecasting a pointer to a structure to become a pointer to another structure, something that is valid if the structures actually correspond to C++ objects that share an inheritance relationship.

C.hh user interface

The .hh file is the interface definition file and has to be included in client implementation files. For the ccstub.hh file, it's the declaration of the C (not C++ actually) routines that are defined in the

cstub.cc file

These are glue routines that forward the calls to the appropriate C++ object function members.

The .hh file includes a bunch of other .hh files (e.g. colias/F_Node.hh). These .hh files are the interface definitions for the classes. Somewhat confusingly, in C++ you have to specify both the public and private interface in the .hh file - pretty silly really.

Automatic Generation of Farfalla I/O

Jim: I was imagining someone at FNAL say adding automatic generation of I/O routines to Farfalla, or emitting them via extensions to the IDL compiler...

Dave: Sounds good to me. I'm happy to go along with that concept. One problem with the automatic generation of the I/O routines from the IDL interface is that that interface only specifies the public interface via accessor functions. It says nothing at all about the internal data members, only how they are accessed. Thus it doesn't deal with any bit packing or other fancy operations (e.g. you might return the module & channel ids as longs, but they might in fact be packed fields within the data member. IDL won't specify that.

Automatic eligibility for I/O

Jim: By the way, to the extent that Farfalla nodes have nicely hidden dynamic allocation/deallocation from such as myself, I'm surprised one wouldn't try to have classes inherit that from them, rather than creating the objects from scratch and then copying them into nodes later? Perhaps I am in the old ZEBRA philosophy of everything is eligible to be written unless forcibly dropped...

Dave: Basically, that's the approach we're sort of taking. Most of the "temporary" objects do in fact inherit from F_Node (actually DATColiasNode) so they are elligable for output.

Example of Fortran 90 Access to Farfalla data

Here's a trivial F-90 subroutine that accesses data within an event:

    SUBROUTINE f90_event( handle )
    USE colias_module
    IMPLICIT NONE
    TYPE(F_Node_handle), INTENT(IN) :: handle
    TYPE(F_Node_handle), POINTER :: rawNode
    TYPE(F_Node_handle), POINTER :: svtNode
    TYPE(DATSVTRawNode_handle), POINTER :: svtRaw
    TYPE(DATSVTDigi_handle), POINTER :: aDigi
    TYPE(DATSVTDigi) :: bDigi
    INTEGER :: nDigis, index
    rawNode => F_Node_getChild( handle, DATRawDataNode_type, 0 )
    svtNode => F_Node_getChild( rawNode, DATSVTRawNode_type, 0 )
    svtRaw  => DATSVTRawNode_from_F_Node( svtNode )
    nDigis   =  DATSVTRawNode_nDigis( svtRaw )
    PRINT *,"nDigis=",nDigis
    DO index = 1, nDigis
	aDigi => DATSVTRawNode_digi( svtRaw, index-1 )
	PRINT *,"Digi ", index
	PRINT *,"  aDigi.channel ", DATSVTDigi_channel( aDigi )
	CALL DATSVTDigi_toF90( aDigi, bDigi )
	PRINT *,"  bDigi.channel ", bDigi % channel
    END DO
    RETURN
    END

Jim Linnemann