The "Hello" class is useful for writing messages to the screen. So that clients can also write messages to printers and disk files, this example references two additional classes: "Printer" and "Disk." The "Printer" class will manage messages to a printer, and the "Disk" class will manage messages sent to files. These classes can be defined as follows:
#include <somobj.idl> interface Printer : SOMObject { void stringToPrinter(in string s) ; // This method writes a string to a printer. }; #include <somobj.idl> interface Disk : SOMObject { void stringToDisk(in string s) ; // This method writes a string to disk. };
This example assumes the "Printer" and "Disk" classes are defined separately (in "print.idl" and "disk.idl," for example), are implemented in separate files, and are linked with the other example code. Given the implementations of the "Printer" and "Disk" interfaces, the "Hello" class can use them by inheriting from them, as illustrated next.
#include <disk.idl> #include <printer.idl> interface Hello : Disk, Printer { void sayHello(); attribute string msg; enum outputTypes {screen, printer, disk}; // Declare an enumeration for the different forms of output attribute outputTypes output; // The current form of output #ifdef __SOMIDL__ implementation { somDefaultInit: override, init; }; #endif //# __SOMIDL__ };
Notice that SOMObject is not listed as a parent of "Hello" above, because SOMObject is a parent of "Disk" (and of "Printer").
The IDL specification above declares an enumeration "outputTypes" for the different forms of output, and an attribute "output" whose value will depend on where the client wants the output of the "sayHello" method to go.
Note: SOM IDL allows the use of structures, unions (though with a syntax different from C or C++), enumerations, constants, and typedefs, both inside and outside the body of an interface statement. Declarations that appear inside an interface body will be emitted in the header file (that is, in "hello.h" or "hello.xh"). Declarations that appear outside of an interface body do not appear in the header file (unless required by a special #pragma directive; see the SOM Compiler options in Chapter 4).
SOM IDL also supports all of the C and C++ preprocessor directives, including conditional compilation, macro processing, and file inclusion.
Unfortunately, when this is done, the implementation for somDefaultInit is not correctly updated to reflect the addition of two new parents to "Hello." This is because the implementation file emitter never changes the bodies of existing method procedures. As a result, method procedures for initializer methods are not given new parent calls when the parents of a class are changed. One way to deal with this (when the parents of a class are changed) is to temporarily rename the method procedure for initializer methods, and then run the implementation emitter. Once this is done, the code in the renamed methods can be merged into the new templates, which will include all the appropriate parent method calls. When this is done here, the new implementation for somDefaultInit would appear as:
SOM_Scope void SOMLINK somDefaultInit(Hello somSelf, somInitCtrl *ctrl) { HelloData *somThis; /* set by BeginInitializer */ somInitCtrl globalCtrl; somBooleanVector myMask; HelloMethodDebug("Hello", "somDefaultInit"); Hello_BeginInitializer_somDefaultINit; Hello_Init_Disk_somDefaultInit(somSelf, ctrl); Hello_Init_Printer_somDefaultInit(somSelf, ctrl); /* * local Hello initialization code added by programmer /* __set_msg(somSelf, "Initial Message"); }
SOM_Scope void SOMLINK sayHello(Hello somSelf, Environment *ev) { /* HelloData *somThis = HelloGetData(somSelf) ; */ HelloMethodDebug("Hello","sayHello") ; switch (__get_output(somSelf, ev) ) { /* for C++, use: somSelf->_get_output(ev) */ case Hello_screen: printf("%s\n", __get_msg(somSelf, ev) ); /* for C++, use: somSelf->_get_msg(ev) */ break; case Hello_printer: _stringToPrinter(somSelf, ev, __get_msg(somSelf, ev) ); /* for C++, use: * somSelf->stringToPrinter(ev, somSelf->_get_msg(ev) ); */ break; case Hello_disk: _stringToDisk(somSelf, ev, __get_msg(somSelf, ev) ); /* for C++, use: * somSelf->stringToDisk(ev, somSelf->_get_msg(ev) ); */ break; } }
The "switch" statement invokes the appropriate method depending on the value of the "output" attribute. Notice how the "case" statements utilize the enumeration values of "outputTypes" declared in "hello.idl" by prefacing the enumeration names with the class name (Hello_screen, Hello_printer, and Hello_disk).
#include <hello.h> /* for C++, use "hello.xh" and <stdio.h> */ int main(int argc, char *argv[]) { Hello a = HelloNew(); Environment *ev = somGetGlobalEnvironment(); /*Invoke "sayHello" on an object and use each output */ _sayHello(a, ev) ; /* for c++, use:a->sayHello(ev);*/ __set_output(a, ev, Hello_printer); /* C++: a->_set_output(ev,Hello_printer);*/ _sayHello(a, ev); __set_output(a, ev, Hello_disk); /* C++:a->_set_output(ev,Hello-disk); */ _sayHello(a, ev) ; _somFree(a0 ; /* for C++, use: a->somFree(); */ return (0); }
Initial Message Initial Message - goes to a Printer Initial Message - goes to Disk
This tutorial has described features of SOM IDL that will be useful to C and C++ programmers. SOM IDL also provides features such as full type checking, constructs for declaring private methods, and constructs for defining methods that receive and return pointers to structures. Chapter 4, "SOM IDL and the SOM Compiler" gives complete description of the SOM IDL syntax and also describes how to use the SOM Compiler. In addition, Chapter 5, "Implementing Classes in SOM," provides helpful information for completing the implementation template, for using initializer (somDefaultInit or user-defined initialization methods), for defining SOM class libraries, and for customizing various aspects of SOMobjects execution.