Jump to content

Implementing Classes in SOM

From EDM2
System Object Model Programming Guide
  1. About This Book
  2. Introduction to the SOMobjects Developer Toolkit
  3. Tutorial for Implementing SOM Classes
  4. Using SOM Classes in Client Programs
  5. SOM IDL and the SOM Compiler
  6. Implementing Classes in SOM
  7. Distributed SOM (DSOM)
  8. The SOM Interface Repository Framework
  9. The Metaclass Framework
  10. The Event Management Framework
  11. SOMobjects Error Codes
  12. SOM IDL Language Grammar
  13. Implementing Sockets Subclasses
  14. Glossary

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

This chapter begins with a more in-depth discussion of SOM concepts and the SOM run-time environment than was appropriate in Tutorial for Implementing SOM Classes. Subsequent sections then provide information about completing an implementation template file, updating the template file, compiling and linking, packaging classes in libraries, and other useful topics for class implementors. During this process, you can refer to Chapter 4, "SOM IDL and the SOM Compiler," if you want to read the reference information or see the full syntax related to topics discussed in this chapter. The current chapter ends with topics describing how to customize SOMobjects execution in various ways.

The SOM Run-Time Environment

The SOMobjects Developer Toolkit provides

  • The SOM Compiler, used when creating SOM class libraries, and
  • The SOM run-time library, for using SOM classes at execution time.

The SOM run-time library provides a set of functions used primarily for creating objects and invoking methods on them. The data structures and objects that are created, maintained, and used by the functions in the SOM run-time library constitute the SOM run-time environment.

A distinguishing characteristic of the SOM run-time environment is that SOM classes are represented by run-time objects; these objects are called class objects. By contrast, other object-oriented languages such as C++ treat classes strictly as compile-time structures that have no properties at run time. In SOM, however, each class has a corresponding run-time object. This has three advantages: First, application programs can access information about a class at run time, including its relationships with other classes, the methods it supports, the size of its instances, and so on. Second, because much of the information about a class is established at run time rather than at compile time, application programs needn't be recompiled when this information changes. Finally, because class objects can be instances of user-defined classes in SOM, users can adapt the techniques for subclassing and inheritance in order to build object-oriented solutions to problems that are otherwise not easily addressed within an OOP context.

Run-time environment initialization

When the SOM run-time environment is initialized, four primitive SOM objects are automatically created. Three of these are class objects (SOMObject, SOMClass, and SOMClassMgr), and one is an instance of SOMClassMgr, called the SOMClassMgrObject. Once loaded, application programs can invoke methods on these class objects to perform tasks such as creating other objects, printing the contents of an object, freeing objects, and the like. These four primitive objects are discussed below.

In addition to creating the four primitive SOM objects, initialization of the SOM run-time environment also involves initializing global variables to hold data structures that maintain the state of the environment. Other functions in the SOM run-time library rely on these global variables.

For application programs written in C or C++ that use the language-specific bindings provided by SOM, the SOM run-time environment is automatically initialized the first time any object is created. Programmers using other languages must initialize the run-time environment explicitly by calling the somEnvironmentNew function (provided by the SOM run-time library) before using any other SOM functions or methods.

SOMObject class object

SOMObject is the root class for all SOM classes. It defines the essential behavior common to all SOM objects. All user-defined SOM classes are derived, directly or indirectly, from this class. That is, every SOM class is a subclass of SOMObject or of some other class derived from SOMObject. SOMObject has no instance variables, thus objects that inherit from SOMObject incur no size increase. They do inherit a suite of methods that provide the behavior required of all SOM objects.

SOMClass class object

Because SOM classes are run-time objects, and since all run-time objects are instances of some class, it follows that a SOM class object must also be an instance of some class. The class of a class is called a metaclass. Hence, the instances of an ordinary class are individuals (nonclasses), while the instances of a metaclass are class objects.

In the same way that the class of an object defines the "instance methods" that the object can perform, the metaclass of a class defines the "class methods" that the class itself can perform. Class methods (sometimes called factory methods or constructors) are performed by class objects. Class methods perform tasks such as creating new instances of a class, maintaining a count of the number of instances of the class, and other operations of a "supervisory" nature. Also, class methods facilitate inheritance of instance methods from parent classes. For information on the distinction between parent classes and metaclasses, see the section "Parent Class vs. metaclass," later in this chapter.

SOMClass is the root class for all SOM metaclasses. That is, all SOM metaclasses must be subclasses of SOMClass or of some metaclass derived from SOMClass. SOMClass defines the essential behavior common to all SOM class objects. In particular, SOMClass provides:

  • Six class methods for creating new class instances: somNew, somNewNoInit, somRenew, somRenewNoInit, somRenewNoZero and somRenewNoInitNoZero.
  • A number of class methods that dynamically obtain or update information about a class and its methods at run time, including:
    • somInitMIClass, for implementing multiple inheritance from parent classes,
    • somOverrideSMethod, for overriding inherited methods, and
    • somAddStaticMethod and somAddDynamicMethod, for including new methods.

SOMClass is a subclass (or child) of SOMObject. Hence, SOM class objects can also perform the same set of basic instance methods common to all SOM objects. This is what allows SOM classes to be real objects in the SOM run-time environment. SOMClass also has the unique distinction of being its own metaclass (that is, SOMClass defines its own class methods).

A user-defined class can designate as its metaclass either SOMClass or another user-written metaclass descended from SOMClass. If a metaclass is not explicitly specified, SOM determines one automatically.

SOMClassMgr class object and SOMClassMgrObject

The third primitive SOM class is SOMClassMgr. A single instance of the SOMClassMgr class is created automatically during SOM initialization. This instance is referred to as the SOMClassMgrObject, because it is pointed to by the global variable SOMClassMgrObject. The object SOMClassMgrObject has the responsibility to

  • Maintain a registry (a run-time directory) of all SOM classes that exist within the current process, and to
  • Assist in the dynamic loading and unloading of class libraries.

For C/C++ application programs using the SOM C/C++ language bindings, the SOMClassMgrObject automatically loads the appropriate library file and constructs a run-time object for the class the first time an instance of a class is created. For programmers using other languages, SOMClassMgr provides a method, somFindClass, for directing the SOMClassMgrObject to load the library file for a class and create its class object.

Again, the primitive classes supplied with SOM are SOMObject, SOMClass, and SOMClassMgr. During SOM initialization, the latter class generates an instance called SOMClassMgrObject. The SOMObject class is the parent class of SOMClass and SOMClassMgr. The SOMClass class is the metaclass of itself, of SOMObject, and of SOMClassMgr, which are all class objects at run time. SOMClassMgr is the class of SOMClassMgrObject.

Parent class vs. metaclass

There is a distinct difference between the notions of "parent" (or base) class and "metaclass." Both notions are related to the fact that a class defines the methods and variables of its instances, which are therefore called instance methods and instance variables.

A parent of a given class is a class from which the given class is derived by subclassing. (Thus, the given class is called a child or a subclass of the parent.) A parent class is a class from which instance methods and instance variables are inherited. For example, the parent of class "Dog" might be class "Animal". Hence, the instance methods and variables introduced by "Animal" (such as methods for breathing and eating, or a variable for storing an animal's weight) would also apply to instances of "Dog", because "Dog" inherits these from "Animal", its parent class. As a result, any given dog instance would be able to breath and eat, and would have a weight.

A metaclass is a class whose instances are class objects, and whose instance methods and instance variables (as described above) are therefore the methods and variables of class objects. For this reason, a metaclass is said to define class methods-the methods that a class object performs. For example, the metaclass of "Animal" might be "AnimalMClass", which defines the methods that can be invoked on class "Animal" (such as, to create Animal instances-objects that are not classes, like an individual pig or cat or elephant or dog).

Note: It is important to distinguish the methods of a class object (that is, the methods that can be invoked on the class object, which are defined by its metaclass) from the methods that the class defines for its instances.

To summarize: the parent of a class provides inherited methods that the class's instances can perform; the metaclass of a class provides class methods that the class itself can perform. These distinctions are further summarized below: The distinctions between parent class and metaclass are summarized in A class has both parent classes and a metaclass.

A class has both parent classes and a metaclass


Any class "C" has both a metaclass and one or more parent class(es).

  • The parent class(es) of "C" provide the inherited instance methods that individual instances (objects "O{i}") of class "C" can perform. Instance methods that an instance "O{i}" performs might include (a) initializing itself, (b) performing computations using its instance variables, (c) printing its instance variables, or (d) returning its size. New instance methods are defined by "C" itself, in addition to those inherited from C's parent classes.
  • The metaclass "M"defines the class methods that class "C" can perform. For example, class methods defined by metaclass "M" include those that allow "C" to (a) inherit its parents' instance methods and instance variables, (b) tell its own name, (c) create new instances, and (d) tell how many instance methods it supports. These methods are inherited from SOMClass. Additional methods supported by "M" might allow "C" to count how many instances it creates.
  • Each class "C" has one or more parent classes and exactly one metaclass. (The single exception is SOMObject, which has no parent class.) Parent class(es) must be explicitly identified in the IDL declaration of a class. (SOMObject is given as a parent if no subsequently-derived class applies.) If a metaclass is not explicitly listed, the SOM run time will determine an applicable metaclass.
  • An instance of a metaclass is always another class object. For example, class "C" is an instance of metaclass "M". SOMClass is the SOM-provided metaclass from which all subsequent metaclasses are derived.

A metaclass has its own inheritance hierarchy (through its parent classes) that is independent of its instances' inheritance hierarchies. For example, suppose a series of classes is defined (or derived), stemming from SOMObject. The child class (or subclass) at the end of this line ("C[2]") inherits instance methods from all of its ancestor classes (here, SOMObject and "C[1]"). An instance created by "C2" can perform any of these instance methods. In an analogous manner, a line of metaclasses can be defined, stemming from SOMClass. Just as a new class is derived from an existing class (such as SOMObject), a new metaclass is derived from an existing metaclass (such as SOMClass).

Parent classes and metaclasses each have their own independent inheritance hierrarchies

SOM-derived metaclasses

As previously discussed, a class object can perform any of the class methods that its metaclass defines. New metaclasses are typically created to modify existing class methods or introduce new class method(s). Chapter 8, "Metaclass Framework," discusses metaclass programming.

Three factors are essential for effective use of metaclasses in SOM:

  • First, every class in SOM is an object that is implemented by a metaclass.
  • Second, programmers can define and name new metaclasses, and can use these metaclasses when defining new SOM classes.
  • Finally, and most importantly, metaclasses cannot interfere with the fundamental guarantee required of every OOP system: specifically, any code that executes without method-resolution error on instances of a given class will also execute without method-resolution errors on instances of any subclass of this class.

Surprisingly, SOM is currently the only OOP system that can make this final guarantee while also allowing programmers to explicitly define and use named metaclasses. This is possible because SOM automatically determines an appropriate metaclass that supports this guarantee, automatically deriving new metaclasses by subclassing at run time when this is necessary. As an example, suppose class "A" is an instance of metaclass "AMeta".

Assume that "AMeta" supports a method "bar" and that "A" supports a method "foo" that uses the expression "_bar( _somGetClass(somSelf ) )." That is, method "foo" invokes "bar" on the class of the object on which "foo" is invoked. For example, when method "foo" is invoked on an instance of class "A" (say, object "O{1}"), this in turn invokes "bar" on class "A" itself.

Now consider what happens if class "A" were subclassed by "B," a class that has the explicit metaclass "BMeta" declared in its SOM IDL source file (and assuming "BMeta" is not derived from "AMeta"). Also assume that object "O{2}" is an instance of class "B."

Recall that "AMeta" supports method "bar" and that class "A" supports method "foo" (which incorporates "bar" in its definition). Given the hierarchy described above, an invocation of "foo" on "O {2}" would fail, because metaclass "BMeta" does not support the "bar" method.

Example of Metaclass Incompatibility


There is only one way that "BMeta" can support this specific method-by inheriting it from "AMeta" ("BMeta" could introduce another method named "bar", but this would be a different method from the one introduced by "AMeta"). Therefore, in this example, because "BMeta" is not a subclass of "AMeta", "BMeta" cannot be allowed to be the metaclass of "B". That is, "BMeta" is not compatible with the requirements placed on "B" by the fundamental principle of OOP referred to above. This situation is referred to as metaclass incompatibility.

SOM does not allow hierarchies with metaclass incompatibilities. Instead, SOM automatically builds derived metaclasses when this is necessary. For example, SOM would create a "DerivedMeta" metaclass that has both "AMeta" and "BMeta" as parents. This ensures that the invocation of method "foo" on instances of class "B" will not fail, and also ensures that the desired class methods provided by "BMeta" will be available on class "B".

Example of a Derived Metaclass

There are three important aspects of SOM's approach to derived metaclasses:

  • First, the creation of SOM-derived metaclasses is integrated with programmer-specified metaclasses. If a programmer-specified metaclass already supports all the class methods and variables needed by a new class, then the programmer-specified metaclass will be used as is.
  • Second, if SOM must derive a different metaclass than the one explicitly indicated by the programmer (in order to support all the necessary class methods and variables), then the SOM-derived metaclass inherits from the explicitly indicated metaclass first. As a result, the method procedures defined by the specified metaclass take precedence over other possibilities (see the following section on inheritance and the discussion of resolution of ambiguity in the case of multiple inheritance).
  • Finally, the class methods defined by the derived metaclass invoke the appropriate initialization methods of its parents to ensure that the class variables of its instances are correctly initialized.

As further explanation for the automatic derivation of metaclasses, consider the following multiple-inheritance example. Class "C" (derived from classes "A" and "B") does not have an explicit metaclass declaration in its SOM IDL, yet its parents "A" and "B" do. As a result, class "C" requires a derived metaclass. (If you still have trouble following the reasoning behind derived metaclasses, ask yourself the following question: What class should "C" be an instance of? After a bit of reflection, you will conclude that, if SOM did not build the derived metaclass, you would have to do so yourself.)

Multiple Inheritance requires Derived Metaclasses

In summary, SOM allows and encourages the definition and explicit use of named metaclasses. With named metaclasses, programmers can not only affect the behavior of class instances by choosing the parents of classes, but they can also affect the behavior of the classes themselves by choosing their metaclasses. Because the behavior of classes in SOM includes the implementation of inheritance itself, metaclasses in SOM provide an extremely flexible and powerful capability allowing classes to package solutions to problems that are otherwise very difficult to address within an OOP context.

At the same time, SOM is unique in that it relieves programmers of the responsibility for avoiding metaclass incompatibility when defining a new class. At first glance, this might seem to be merely a useful (though very important) convenience. But, in fact, it is absolutely essential, because SOM is predicated on binary compatibility with respect to changes in class implementations.

A programmer might, at one point in time, know the metaclasses of all ancestor classes of a new subclass, and, as a result, be able to explicitly derive an appropriate metaclass for the new class. Nevertheless, SOM must guarantee that this new class will still execute and perform correctly when any of its ancestor class's implementations are changed (which could even include specifying different metaclasses). Derived metaclasses allow SOM to make this guarantee. A SOM programmer need never worry about the problem of metaclass incompatibility; SOM does this for the programmer. Instead, explicit metaclasses can simply be used to "add in" whatever behavior is desired for a new class. SOM automatically handles anything else that is needed. Chapter 10 provides useful examples of such metaclasses. A SOM programmer should find numerous applications for the techniques that are illustrated there.

Inheritance

One of the defining aspects of an object model is its characterization of inheritance. This section describes SOM's model for inheritance.

A class in SOM defines an implementation for objects that support a specific interface:

  • The interface defines the methods supported by objects of the class, and is specified using SOM IDL.
  • The implementation defines what instance variables implement an object's state and what procedures implement its methods.

New classes are derived (by subclassing) from previously existing classes through inheritance, specialization, and addition. Subclasses inherit interface from their parent classes: any method available on instances of a class is also available on instances of any class derived from it (either directly or indirectly). Subclasses also inherit implementation (the procedures that implement the methods) from their parent classes unless the methods are overridden (redefined or specialized). In addition, a subclass may introduce new instance methods and instance variables that will be inherited by other classes derived from it.

SOM also supports multiple inheritance. That is, a class may be derived from (and may inherit interface and implementation from) multiple parent classes. Note: Multiple inheritance is available only to SOM classes whose interfaces are specified in IDL, and not to SOM classes whose interfaces are specified in SOM's earlier interface definition language, OIDL. See Appendix B for information on how to automatically convert existing OIDL files to IDL.

It is possible under multiple inheritance to encounter potential conflicts or ambiguities with respect to inheritance. All multiple inheritance models must face these issues, and resolve the ambiguities in some way. For example, when multiple inheritance is allowed, it is possible that a class will inherit the same method or instance variable from different parents (because each of these parents has some common ancestor that introduces the method or instance variable). In this situation, a SOM subclass inherits only one implementation of the method or instance variable. (The implementation of an instance variable within an object is just the location where it is stored. The implementation of a method is a procedure pointer, stored within a method table.) The following illustration addresses the question of which method implementation would be inherited.

Consider this situation: Class "W" defines a method "foo", implemented by procedure "proc1". Class "W" has two subclasses, "X" and "Y". Subclass "Y" overrides the implementation of "foo" with procedure "proc2". Subclass "X" does not override "foo". In addition, classes "X" and "Y" share a common subclass, "Z". That is, the IDL interface statement for class "Z" lists its parents as "X" and "Y" in that order. (These relationships form a diamond shape, with class "W" at the top.)

The question is thus: which implementation of method "foo" does class "Z" inherit-procedure "proc1" defined by class "W", or procedure "proc2" defined by class "Y"? The procedure for performing inheritance that is defined by SOMClass resolves this ambiguity by using the left path precedence rule: when the same method is inherited from multiple ancestors, the procedure used to support the method is the one used by the leftmost ancestor from which the method is inherited. (The ordering of parent classes is determined by the order in which the class implementor lists the parents in the IDL specification for the class.)

Class "Z" inherits the implementation of method "foo" defined by class "W" (procedure "proc1"), rather than the implementation defined by class "Y" (procedure "proc2"), because "X" is the leftmost ancestor of "Z" from which the method "foo" is inherited. This rule may be interpreted as giving priority to classes whose instance interfaces are mentioned first in IDL interface definitions.

If a class implementor decides that the default inherited implementation is not appropriate (for example, procedure "proc2" is desired), then SOM IDL allows the class designer to select the parent whose implementation is desired. For more information concerning this approach, see the Select modifier, which is documented in the topic "Modifier statements" in Chapter 4, "SOM IDL and the SOM Compiler."

Note
Alternatively, an explicit metaclass for "Z" could be introduced to change the way methods are inherited. However, this would be a fairly serious step to take-it would also affect the semantics of inheritance for all of Z's descendant classes.


Another conflict that may arise with the use of multiple inheritance is when two ancestors of a class define different methods (in general, with different signatures) of the same name. For example, suppose Class "X" defines a method "bar" with type T1, and class "Y" defines a method "bar" with type T2. Class "Z" is derived from both "X" and "Y", and "Z" does not override method "bar".

This example illustrates a method name that is "overloaded"-that is, used to name two entirely different methods (note that overloading is completely unrelated to overriding). This is not necessarily a difficult problem to handle. Indeed, the run-time SOM API allows the construction of a class that supports the two different "bar" methods. (They are implemented using two different method-table entries, each of which is associated with its introducing class.)

However, the interface to instances of such classes can not be defined using IDL. IDL specifically forbids the definition of interfaces in which method names are overloaded. Furthermore, within SOM itself, the use of such classes can lead to anomalous behavior unless care is taken to avoid the use of name-lookup method resolution (discussed in the following section), since, in this case, a method name alone does not identify a unique method. For this reason, (statically declared) multiple-inheritance classes in SOM are currently restricted to those whose instance interfaces can be defined using IDL. Thus, the above example cannot be constructed with the aid of the SOM Compiler.

Method Resolution

Method resolution is the step of determining which procedure to execute in response to a method invocation. For example, consider this scenario:

  • Class "Dog" introduces a method "bark", and
  • A subclass of "Dog", called "BigDog", overrides "bark", and
  • A client program creates an instance of either "Dog" or "BigDog" (depending on some run-time criteria) and invokes method "bark" on that instance.

Method resolution is the process of determining, at run time, which method procedure to execute in response to the method invocation (either the method procedure for "bark" defined by "Dog", or the method procedure for "bark" defined by "BigDog"). This determination depends on whether the receiver of the method (the object on which it is invoked) is an instance of "Dog" or "BigDog" (or perhaps depending on some other criteria).

SOM allows class implementors and client programs considerable flexibility in deciding how SOM performs method resolution. In particular, SOM supports three mechanisms for method resolution, described in order of increased flexibility and increased computational cost: offset resolution, name-lookup resolution, and dispatch-function resolution.

Offset resolution

When using SOM's C and C++ language bindings, offset resolution is the default way of resolving methods, because it is the fastest. For those familiar with C++, it is roughly equivalent to the C++ "virtual function" concept.

Although offset resolution is the fastest technique for method resolution, it is also the most constrained. Specifically, using offset resolution requires these constraints:

  • The name of the method to be invoked must be known at compile time,
  • The name of the class that introduces the method must be known at compile time (although not necessarily by the programmer), and
  • The method to be invoked must be part of the introducing class's static (IDL) interface definition.

To perform offset method resolution, SOM first obtains a method token from a global data structure associated with the class that introduced the method. This data structure is called the ClassData structure. It includes a method token for each method the class introduces. The method token is then used as an "index" into the receiver's method table, to access the appropriate method procedure. Because it is known at compile time which class introduces the method and where in that class's ClassData structure the method's token is stored, offset resolution is quite efficient. The cost of offset method resolution is currently about twice the cost of calling a C function using a pointer loaded with the function address.

An object's method table is a table of pointers to the procedures that implement the methods that the object supports. This table is constructed by the object's class and is shared among the class instances. The method table built by class (for its instances) is referred to as the class's instance method table. This is useful terminology, since, in SOM, a class is itself an object with a method table (created by its metaclass) used to support method calls on the class.

Usually, offset method resolution is sufficient; however, in some cases, the more flexible name-lookup resolution is required.

Name-lookup resolution

Name-lookup resolution is similar to the method resolution techniques employed by Objective-C and Smalltalk. It is currently about five times slower than offset resolution. It is more flexible, however. In particular, name-lookup resolution, unlike offset resolution, can be used when:

  • The name of the method to be invoked isn't known until run time, or
  • The method is added to the class interface at run time, or
  • The name of the class introducing the method isn't known until run time.

For example, a client program may use two classes that define two different methods of the same name, and it might not be known until run time which of the two methods should be invoked (because, for example, it will not be known until run time which class's instance the method will be applied to).

Name-lookup resolution is always performed by a class, so it requires a method call. (Offset resolution, by contrast, requires no method calls.) To perform name-lookup method resolution, the class of the intended receiver object obtains a method procedure pointer for the desired method that is appropriate for its instances. In general, this will require a name-based search through various data structures maintained by ancestor classes.

Offset and name-lookup resolution achieve the same net effect (that is, they select the same method procedure); they just achieve it differently (via different mechanisms for locating the method's method token). Offset resolution is faster, because it does not require searching for the method token, but name-lookup resolution is more flexible.

When defining (in SOM IDL) the interface to a class of objects, the class implementor can decide, for each method, whether the SOM Compiler will generate usage bindings that support name-lookup resolution for invoking the method. Regardless of whether this is done, however, application programs using the class can have SOM use either technique, on a per-method-call basis. Chapter 3, "Using SOM Classes in Client Programs," describes how client programs invoke methods.

Dispatch-function resolution

Dispatch-function resolution is the slowest, but most flexible, of the three method-resolution techniques. Dispatch functions permit method resolution to be based on arbitrary rules associated with the class of which the receiving object is an instance. Thus, a class implementor has complete freedom in determining how methods invoked on its instances are resolved.

With both offset and name-lookup resolution, the net effect is the same-the method procedure that is ultimately selected is the one supported by the class of which the receiver is an instance. For example, if the receiver is an instance of class "Dog", then Dog's method procedure will be selected; but if the receiver is an instance of class "BigDog", then BigDog's method procedure will be selected.

By contrast, dispatch-function resolution allows a class of instances to be defined such that the method procedure is selected using some other criteria. For example, the method procedure could be selected on the basis of the arguments to the method call, rather than on the receiver. For more information on dispatch-function resolution, see the description and examples for the somDispatch and somOverrideMTab methods in the SOMobjects Developer Toolkit: Programmers Reference Manual.

Customizing Method Resolution

Customizing method resolution requires the use of metaclasses that override SOMClass methods. This is not recommended without use of the Cooperative Metaclass that guarantees correct operation of SOMobjects in conjunction with such metaclasses. SOMobjects users who require this functionality should request access to the experimental Cooperative Metaclass used to implement the SOMobjects Metaclass Framework. Metaclasses implemented using the Cooperative Metaclass may have to be reprogrammed in the future when SOMobjects introduces an oficially supported Cooperative Metaclass.

The four kinds of SOM methods

SOM supports four different kinds of methods: static methods, nonstatic methods, dynamic methods, and direct-call procedures. The following paragraphs explain these four method categories and the kinds of method resolution available for each.

Static methods

These are similar in concept to C++ virtual functions. Static methods are normally invoked using offset resolution via a method table, as described above, but all three kinds of method resolution are applicable to static methods. Each different static method available on an object is given a different slot in the object's method table. When SOMobjects Toolkit language bindings are used to implement a class, the SOM IDL method modifier can be specified to indicate that a given method is static; however, this modifier is rarely used since it is the default for SOM methods.

Static methods introduced by a class can be overridden (redefined) by any descendant classes of the class. When SOMobjects language bindings are used to implement a class, the SOM IDL override modifier is specified to indicate that a class overrides a given inherited method. When a static method is resolved using offset resolution, it is not important which interface is accessing the method - the actual class of the object determines the method procedure that is selected.

Note: All SOM IDL modifiers are described in the topic "Modifier statements" in Chapter 4, "SOM IDL and the SOM Compiler."

Nonstatic methods

These methods are similar in concept to C++ nonstatic member functions (that is, C++ functions that are not virtual member functions and are not static member functions). Nonstatic methods are normally invoked using offset resolution, but all three kinds of method resolution are applicable to nonstatic methods. When the SOMobjects language bindings are used to implement a class, the SOM IDL nonstatic modifier is used to indicate that a given method is nonstatic.

Like static methods, nonstatic methods are given individual positions in method tables. However, nonstatic methods cannot be overridden. Instead, descendants of a class that introduces a nonstatic method can use the SOM IDL reintroduce modifier to "hide" the original nonstatic method with another (nonstatic or static) method of the same name. When a nonstatic method is resolved, selection of the specific method procedure is determined by the interface that is used to access the method.

Dynamic methods

These methods are not declared when specifying an object interface using IDL. Instead, they are registered with a class object at run time using the method somAddDynamicMethod. Because there is no way for SOM to know about dynamic methods before run time, offset resolution is not available for dynamic methods. Only name-lookup or dispatch-function resolution can be used to invoke dynamic methods. Dynamic methods cannot be overridden.

Direct-call procedures

These are similar in concept to C++ static member functions. Direct-call procedures are not given positions in SOM method tables, but are accessed directly from a class's ClassData structure. Strictly speaking, none of the previous method-resolution approaches apply for invoking a direct-call procedure, although SOMobjects language bindings provide the same invocation syntax for direct-call procedures as for static or nonstatic methods. Direct-call procedures cannot be overridden, but they can be reintroduced. When SOMobjects language bindings are used to implement a class, the SOM IDL procedure modifier is used to indicate that a given method is a direct-call procedure. Note: Methods having the procedure modifier cannot be invoked remotely using DSOM.

Implementing SOM Classes

The implementation template

Stub procedures for methods

Extending the implementation template

Accessing internal instance variables

Making parent method calls

Converting C++ classes to SOM classes

Running incremental updates of the implementation template file

Considerations to ensure that updates work

If you change the parents of a class...

Compiling and linking

Initializing and Uninitializing Objects

       Initializer methods
           Declaring new initializers in SOM IDL
           Considerations re: 'somInit' initialization from earlier SOM releases
           Implementing initializers
           Selecting non-default ancestor initializer calls
           Using initializers when creating new objects 
       Uninitialization
           Using 'somDestruct' 
       A complete example
           Implementation code 
       Customizing the initialization of class objects 

Creating a SOM Class Library

General guidelines for class library designers

Types of class libraries

Building export files

Specifying the initialization function

           Using Windows class libraries 

Creating the import library

Customizing Memory Management

Customizing Class Loading and Unloading

Customizing class initialization

Customizing DLL loading

Customizing DLL unloading

Customizing Character Output

Customizing Error Handling

Customizing Mutual Exclusion Services (Thread Safety)

Customizing Multi-threading Services