SOM's OOP Model from the SOMobjects Developer Toolkit

From EDM2
Jump to: navigation, search

Written by Gordon Zeglinski

Introduction

This column deviates from the usual C++ stuff; instead, we will be exploring SOM's OOP model. More precisely, the SOMobjects Developer Toolkit, which ships with SOM 2 and DSOM, will be examined.

What is SOM?

SOM, the System Object Model, is a language neutral object model. An Object in SOM is defined using an Interface Definition Language. The interface language is then "compiled" into a language specific form. For instance, if one were using C to implement the object, the SOM compiler would be used to produce .C, .IH, and .H files. The language specific form created by the SOM compiler has function stubs that the programmer would fill in. These stubs are the bodies to the member functions defined in the IDL. Because SOM objects can be used across different languages and compilers, they use the same linkage as OS/2's API and their names are not mangled like in C++.

OS/2 2.11 and previous versions of OS/2 2.x use SOM 1 in the Workplace Shell (WPS). SOM 1 is also central to the design of VX-REXX, and VisPro/REXX. (Of course, any WPS based application is also SOM based.) Not too worry, SOM 1 based applications will still run when SOM 2 is installed because SOM 2 is backwards compatible to SOM 1. The following list specifies some of the ways in which SOM 2 differs from SOM 1:

  1. allows multiple inheritance
  2. allows derived metaclasses
  3. is CORBA compliant
  4. methods can return structures
  5. multiple classes can be packaged within a single file

Objects in SOM can be packaged in DLLs or in EXEs. Using DLLs offers the greatest flexibility. In fact, this is how one can extend the WPS and the other SOM based programs mentioned above.

DSOM

DSOM (Distributed System Object Model) allows SOM objects to be manipulated across processes. These processes can even be on different machines. In theory, this could make extending the WPS much easier than it presently is. If the WPS is writen to use DSOM objects, then it will be posible to write WPS objects that can run in their own EXE and debug that EXE instead of the whole WPS.

Note: the WARP II beta ships with SOM 2.

The toolkit ships with a few goodies. The first item, called "Replication Frameworks", allows an object to exist in multiple processes at the same time, even across networks. Changes to any replicated object will be relayed to all replicas of the object. The network type and other details are abstracted from the programmer. Next is the "Persistence Frameworks"; it is used to stored objects on to disk. The "Event Management Frameworks" can be used to encapsulate event based activities, like the PM message loop.

Now that we have briefly looked at some of the features in the SOM toolkit, we'll move on to a quick look at the SOM OOP model.

SOM OOP vs C++ OPP

First, let's take a quick look at how the two OOP models differ. SOM uses a more runtime oriented OOP model. That is, the exact function that is being called, or the size of the object may not be known until the code is executed. Methods are called using one of the following schemes:

  1. Offset resolution (default)
  2. Name-lookup resolution
  3. Dispatch-function resolution

The above list is ordered by decreasing execution speed. Offset resolution is similar to "virtual functions" used in C++. The name-lookup method allows a method whose name is not known until run-time to be called. The most flexible and time consuming resolution method uses the dispatch-function. This method allows methods to be called using application specific rules. As mentioned before, method names are not mangled like they are in C++; this is because, unlike C++, SOM does not allow operators to be overloaded.

Metaclasses

Coming from a C++ background, this is where things get confusing. In C++, the most fundamental object is a class. Class methods or data members were declared as "static" member of the class. This is not the case in SOM. Classes are instances of metaclasses, and objects are instances of classes. The metaclass contains all the class specific functions and data. Roughly speaking, a metaclass can contain data and methods that were either explicitly of implicitly defined as being static in C++.

Note: constructors are implicitly static member functions in C++.

A Simple Example

We'll take the "Hello World" example created by IBM and add some class data and methods to it. The source code presented here will have the IBM disclaimers stripped, if you really want to read them, see the source code files. We start by looking at HELLO.IDL.

#ifndef hello_h
#define hello_h

#include <somcls.idl>

interface M_Hello;
interface Hello : SOMObject
{
    string hello_();
    attribute string hellomsg;

   void sayHello();

#ifdef __SOMIDL__
implementation
{
    releaseorder: hello_, _get_hellomsg, _set_hellomsg,sayHello;
    callstyle=oidl;
    filestem = hello;
    metaclass = M_Hello;
    somInit: override;
};
#endif /* __SOMIDL__ */
};

interface M_Hello : SOMClass
{
    attribute string ClassData;

    Hello HelloCreate(in string msg);
    // This method creates an instance of the Hello class and
    // uses the value of "msg" to initialise it.
#ifdef __SOMIDL__
implementation
{
   releaseorder: HelloCreate,_get_ClassData,_set_ClassData;
   callstyle=oidl;
   filestem = hello;
   functionprefix=M_;
   somInitMIClass: override;
   somInit: override; // just a test for parent call macros
};
#endif /* __SOMIDL__ */
};

#endif /* hello_h */

To the Hello class, I have added the member void sayHello(). To the M_Hello metaclass, I have added the member attribute string ClassData. An attribute is merely a data member that has _get_ and _set_ methods automatically defined for it. The original code can be found in the \som\samples\somk\cpp\derived directory if the samples were installed with the toolkit. The code for sayHello() is shown below. This code illustrates how to access instance data and class data. The code below is written using the C++ bindings.

SOM_Scope void  SOMLINK sayHello(Hello *somSelf)
{
    //the folowing two lines are created by the som compiler.
    HelloData *somThis = HelloGetData(somSelf);
    HelloMethodDebug("Hello","sayHello");

    // Get the CLASS instance
    M_Hello *helloCls=(M_Hello *)somSelf->somGetClass();

    printf("%s an instance of
%s\n",somSelf->_get_hellomsg(),helloCls->_get_ClassData());

}

It is worth noting that the data/attributes are accessed by calling methods rather than by explicitly using the attributes name. Also, class data is accessed by using a pointer to an instance of the M_Hello metaclass.

Note: M_Hello is the metaclass for Hello.

Now lets put this code to work.

int main(int argc, char *argv[])
{
   Hello *a,*b,*c;

   // create an instance of the M_Hello metaclass

   M_Hello
*helloClsObj=HelloNewClass(Hello_MajorVersion,Hello_MinorVersion);

   //set the class data
   helloClsObj->_set_ClassData("Class 1");

   //call the M_Hello class method HelloCreate to create an instance of
   //the class Hello

   a=helloClsObj->HelloCreate("Hello from A");
   b=helloClsObj->HelloCreate("Hello from B");
   c=helloClsObj->HelloCreate("Hello from C");

   //call the sayHello method for each object
   a->sayHello();
   b->sayHello();
   c->sayHello();

   // free up each of the objects
   a->somFree();
   b->somFree();
   c->somFree();

   return 0;
}

Wrapping Things Up

We briefly looked at some of the components of the SOMobjects Developers Toolkit. In adition a simple SOM 2 example was presented. In the next issue, we will look at creating a SOM class that encapsulates the INI interface.