Tutorial for Implementing SOM Classes

This tutorial contains five examples showing how SOM classes can be implemented to achieve various functionality. Obviously, for any person who wishes to become a class implementor, this tutorial is essential. However, even for those programmers who expect only to use SOM classes that were implemented by others, the tutorial is also necessary, as it presents several concepts that will help clarify the process of using SOM classes.

Basic Concepts of the System Object Model (SOM)
The System Object Model (SOM), provided by the SOMobjects Developer Toolkit, is a set of libraries, utilities, and conventions used to create binary class libraries that can be used by application programs written in various object-oriented programming languages, such as C++ and Smalltalk, or in traditional procedural languages, such as C and Cobol. The following paragraphs introduce some of the basic terminology used when creating classes in SOM:


 * An object is an OOP entity that has behavior (its methods or operations) and state (its data values). In SOM, an object is a run-time entity with a specific set of methods and instance variables. The methods are used by a client programmer to make the object exhibit behavior (that is, to do something), and the instance variables are used by the object to store its state. (The state of an object can change over time, which allows the object's behavior to change.) When a method is invoked on an object, the object is said to be the receiver or target of the method call.


 * An object's implementation is determined by the procedures that execute its methods, and by the type and layout of its instance variables. The procedures and instance variables that implement an object are normally encapsulated (hidden from the caller), so a program can use the object's methods without knowing anything about how those methods are implemented. Instead, a user is given access to the object's methods through its interface (a description of the methods in terms of the data elements required as input and the type of value each method returns).


 * An interface through which an object may be manipulated is represented by an object type. That is, by declaring a type for an object variable, a programmer specifies the interface that is intended to be used to access that object. SOM IDL (the SOM Interface Definition Language) is used to define object interfaces. The interface names used in these IDL definitions are also the type names used by programmers when typing SOM object variables.


 * In SOM, as in most approaches to object-oriented programming, a class defines the implementation of objects. That is, the implementation of any SOM object (as well as its interface) is defined by some specific SOM class. A class definition begins with an IDL specification of the interface to its objects, and the name of this interface is used as the class name as well. Each object of a given class may also be called an instance of the class, or an instantiation of the class.


 * Inheritance, or class derivation, is a technique for developing new classes from existing classes. The original class is called the base class, or the parent class, or sometimes the direct ancestor class. The derived class is called a child class or a subclass. The primary advantage of inheritance is that a derived class inherits all of its parent's methods and instance variables. Also through inheritance, a new class can override (or redefine) methods of its parent, in order to provide enhanced functionality as needed. In addition, a derived class can introduce new methods of its own. If a class results from several generations of successive class derivation, that class "knows" all of its ancestors's methods (whether overridden or not), and an object (or instance) of that class can execute any of those methods.


 * SOM classes can also take advantage of multiple inheritance, which means that a new class is jointly derived from two or more parent classes. In this case, the derived class inherits methods from all of its parents (and all of its ancestors), giving it greatly expanded capabilities. In the event that different parents have methods of the same name that execute differently, SOM provides ways for avoiding conflicts.


 * In the SOM run time, classes are themselves objects. That is, classes have their own methods and interfaces, and are themselves defined by other classes. For this reason, a class is often called a class object. Likewise, the terms class methods and class variables are used to distinguish between the methods/variables of a class object vs. those of its instances. (Note that the type of an object is not the same as the type of its class, which as a "class object" has its own type.)


 * A class that defines the implementation of class objects is called a metaclass. Just as an instance of a class is an object, so an instance of a metaclass is a class object. Moreover, just as an ordinary class defines methods that its objects respond to, so a metaclass defines methods that a class object responds to. For example, such methods might involve operations that execute when a class (that is, a class object) is creating an instance of itself (an object). Just as classes are derived from parent classes, so metaclasses can be derived from parent metaclasses, in order to define new functionality for class objects.


 * The SOM system contains three primitive classes that are the basis for all subsequent classes:


 * SOMObject : the root ancestor class for all SOM classes,


 * SOMClass : the root ancestor class for all SOM metaclasses, and


 * SOMClassMgr : the class of the SOMClassMgrObject, an object created automatically during SOM initialization, to maintain a registry of existing classes and to assist in dynamic class loading/unloading. SOMClass is defined as a subclass (or child) of SOMObject and inherits all generic object methods; this is why instances of a metaclass are class objects (rather than simply classes) in the SOM run time.

SOM classes are designed to be language neutral. That is, SOM classes can be implemented in one programming language and used in programs of another language. To achieve language neutrality, the interface for a class of objects must be defined separately from its implementation. That is, defining interface and implementation requires two completely separate steps (plus an intervening compile), as follows:


 * An interface is the information that a program must know in order to use an object of a particular class. This interface is described in an interface definition (which is also the class definition), using a formal language whose syntax is independent of the programming language used to implement the class's methods. For SOM classes, this is the SOM Interface Definition Language (SOM IDL). The interface is defined in a file known as the IDL source file (or, using its extension, this is often called the .idl file).


 * An interface definition is specified within the interface declaration (or interface statement) of the .idl file, which includes:


 * (a) : the interface name (or class name) and the name(s) of the class's parent(s), and


 * (b) : the names of the class's attributes and the signatures of its new methods. (Recall that the complete set of available methods also includes all inherited methods.) Each method signature includes the method name, and the type and order of its arguments, as well as the type of its return value (if any). Attributes are instance variables for which "set" and "get" methods will automatically be defined, for use by the application program. (By contrast, instance variables that are not attributes are hidden from the user.)

Once the IDL source file is complete, the SOM Compiler is used to analyze the .idl file and create the implementation template file, within which the class implementation will be defined. Before issuing the SOM Compiler command, sc, the class implementor can set an environment variable that determines which emitters (output-generating programs) the SOM Compiler will call and, consequently, which programming language and operating system the resulting binding files will relate to. (Alternatively, this emitter information can be placed on the command line for sc.) In addition to the implementation template file itself, the binding files include two language-specific header files that will be #included in the implementation template file and in application program files. The header files define many useful SOM macros, functions, and procedures that can be invoked from the files that include the header files.

The implementation of a class is done by the class implementor in the implementation template file (often called just the implementation file or the template file). As produced by the SOM Compiler, the template file contains stub procedures for each method of the class. These are incomplete method procedures that the class implementor uses as a basis for implementing the class by writing the corresponding code in the programming language of choice.

In summary, the process of implementing a SOM class includes using the SOM IDL syntax to create an IDL source file that specifies the interface to a class of objects - that is, the methods and attributes that a program can use to manipulate an object of that class. The SOM Compiler is then run to produce an implementation template file and two binding (header) files that are specific to the designated programming language and operating system. Finally, the class implementor writes language-specific code in the template file to implement the method procedures.

At this point, the next step is to write the application (or client) program(s) that use the objects and methods of the newly implemented class. (Observe, here, that a programmer could write an application program using a class implemented entirely by someone else.) If not done previously, the SOM compiler is run to generate usage bindings for the new class, as appropriate for the language used by the client program (which may be different from the language in which the class was implemented). After the client program is finished, the programmer compiles and links it using a language-specific compiler, and then executes the program. (Notice again, the client program can invoke methods on objects of the SOM class without knowing how those methods are implemented.)

Development of the Tutorial examples

 * Example 1 - Implementing a simple class with one method : Prints a default message when the "sayHello" method is invoked on an object of the "Hello" class.


 * Example 2 - Adding an attribute to the Hello class :  Defines a "msg" attribute for the "sayHello" method to use. The client program "sets" a message; then the "sayHello" method "gets" the message and prints it. (There is no defined message when an object of the "Hello" class is first created.)


 * Example 3 - Overriding an inherited method : Overrides the SOMobjects method somPrintSelf so that invoking this method on an object of the "Hello" class will not only display the class name and the object's location, but will also include the object's message attribute.


 * Example 4 - Initializing a SOM object : Overrides the default initialization method, somDefaultInit, to illustrate how an object's instance variables can be initialized when the object is created.


 * Example 5 - Using multiple inheritance : Extends the "Hello" class to provide it with multiple inheritance (from the "Disk;" and "Printer" classes.) The "Hello" interface defines an enum and an "output" attribute that takes its value from the enum (either "screen," "printer," or "disk"). The client program "sets" the form of "output" before invoking the "sayHello" method to send a "msg"(defined as in Example 4).

Basic Steps for Implementing SOM Classes
Implementing and using SOM classes in C or C++ involves the following steps, which are explicitly illustrated in the examples of this tutorial:


 * Define the interface to objects of the new class (that is, the interface declaration), by creating a .idl file.
 * Run the SOM Compiler on the .idl file by issuing the sc command to produce the following binding files:


 * Template implementation file
 * a .c file for C programmers, or
 * a .cpp file for C++ programmers;


 * Header file to be included in the implementation file
 * a .ih file for C programmers, or
 * a .xih file for C++ programmers; and


 * Header file to be included in client programs that use the class
 * a .h file for C clients, or
 * a .xh file for C++ clients.

To specify whether the SOM Compiler should produce C or C++ bindings, set the value of the SMEMIT environment variable or use the "-s" option of the sc or somc command, as described in Section 4.3, "The SOM Compiler." By default, the SOM Compiler produces C bindings.


 * 1) Customize the implementation, by adding code to the template implementation file.
 * 2) Create a client program that uses the class.
 * 3) Compile and link the client code with the class implementation, using a C or C++ compiler.
 * 4) Execute the client program.

The following examples illustrate appropriate syntax for defining interface declarations in a .idl file, including designating the methods that the class's instances will perform. In addition, example template implementation files contain typical code that the SOM Compiler produces. Explanations accompanying each example discuss topics that are significant to the particular example; full explanations of the SOM IDL syntax are contained in Chapter 4, "SOM IDL and the SOM Compiler." Customization of each implementation file (step 3) is illustrated in C and C++.

Note:


 * The Tutorial assumes you will work through the examples in order. If you do not do so, the code that the SOM Compiler generates from your revised .idl file may vary slightly from what you see in the Tutorial.


 * When the SOMobjects Toolkit is installed, a choice is made between "somcorba" and "somstars" for the style of C bindings the SOM Compiler will generate. The Tutorial examples use the "somcorba" style, where an interface name used as a type indicates a pointer to an object, as required by strict CORBA bindings. Consequently, as the examples show, a "*" does not explicitly appear for types that are pointers to objects. If your system was installed for "somstars" C bindings, you can set the environment variable SMADDSTAR=1 or use the SOM Compiler option "-maddstar" to request bindings that use explicit pointer stars. For more information, see "Declaring object variables" in Chapter 3, "Using SOM Classes in Client Programs" and "Object types" in Chapter 4, "SOM IDL and the SOM Compiler."