IBM SOMobjects Developers Toolkit for OS/2

Version: 
3.0
Release date: 
Monday, 23 December, 1996

License:

Interface:

The System Object Model (SOM) is a new object-oriented programming technology for building, packaging, and manipulating binary class libraries.

With SOM, class implementers describe the interface for a class of objects (names of the methods it supports, the return types, parameter types, and so forth) in a standard language called the Interface Definition Language (IDL).

They then implement methods in their preferred programming language (which may be either an object-oriented programming language or a procedural language such as C).

This means that programmers can begin using SOM quickly, and also extends the advantages of OOP to programmers who use non-object-oriented programming languages!

This software is distributed as compressed package. You have to download and manually install it; if prerequisites are required, you will have to manually install them too.

Manual installation

Program is distributed as ZIP package: download to temporary directory and unpack to destination folder. Prerequisites include only C/C++ languages. See below for download link(s).

Online documentation:

Following ones are the download links for manual installation:

IBM SOMobjects Developers Toolkit for OS/2 v. 3.0 (23/12/1996, International Business Machines Corporation (IBM)) Readme/What's new
IBM SOMobjects Developer Toolkit - Version 3.0 - README ------------------------------------------------------- December 1996 Release --------------------- 25H7912 (C) COPYRIGHT International Business Machines Corp. 1992,1996 All Rights Reserved Licensed Materials - Property of IBM US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. Welcome to SOMobjects Developer Toolkit - Version 3.0 December 1996 Release =========================================================================== SOMobjects Developer Toolkit is now available for AIX, OS/2, and Windows NT. The SOMobjects Developer Toolkit code, publications, and the latest version of this README are available at: http://www.software.ibm.com/clubopendoc/som30tk.html This file contains information that you need for installing SOMobjects Developer Toolkit and additional information not included in the original product documentation. The following components and function which were provided in the February 1996 Beta release of SOMobjects 3.0 are no longer supported: - IDL Editor and IR Browser - sommak utility - somdoc utility and ipf emitter - Direct-To-SOM Programming - Collection Classes - Event Management Framework - Event Service - Life Cycle Service - Persistent Object Service - Concurrency Control Service - Transaction Service - pregimpl Server Registration GUI - online documentation This README file is divided into the following categories: - Before You Install - Hardware Requirements - Base Software Requirements - Networking Software Requirements - Supported Compilers - Installing SOMobjects Developer Toolkit - Installation on AIX - Installation on OS/2 - Installation on Windows NT - ISO Latin-1 Code Page Conversion - Updated Component Information - General Component Information - SOM Kernel - SOM Emitters - Distributed SOM - Object Services - Trademarks - Your Satisfaction Before You Install ================== Hardware Requirements --------------------- - An IBM or non-IBM hardware platform supporting the required level of the operating system - Display, mouse, and keyboard - OS/2 and Windows NT - At least 16 MB of RAM - At least 30 MB of fixed disk space - AIX - At least 24 MB of RAM - At least 30 MB of fixed disk space Base Software Requirements -------------------------- The following levels of operating system products are supported: - OS/2 Warp Version 3 - AIX Version 4.1.4 or 4.2 with fileset xlC.rte - Microsoft Windows NT 3.51 Networking Software Requirements -------------------------------- When using Distributed SOM, networking software is required. This is true even when DSOM is used on a single workstation for inter-process communication. Distributed SOM requires one of the following network products: - IBM TCP/IP Version 3.0 for OS/2 - IBM AnyNet/2 with NetBIOS or TCP/IP, Version 2.02 with corrective service for APAR IC12389 - TCP/IP as provided in the AIX operating system - TCP/IP as provided in the Windows NT operating system Security Service on OS/2 requires: - LAN Server Version 4.0 with fixpak PTF=IP08182 Supported Compilers ------------------- The following compilers are supported: - IBM VisualAge C++ for OS/2, Version 3.0, FixPack CTC306 - IBM VisualAge C++ for Windows, Version 3.5, FixPack WTC352 - IBM CSet++ for AIX, Version 3.1.4 FixPacks for VisualAge C++ are available on the Web. You can follow links from the VisualAge C++ Home Page: http://www.software.ibm.com/ad/visualage_c++ Note: The target date for CSD2 for VisualAge C++ for Windows is 1/15/97. Installing and Configuring the SOMobjects Developer Toolkit =========================================================== The following is a summary of SOM Installation and Configuration. See Chapter 2 of the Programmer's Guide, Volume 1: SOM and DSOM for complete configuration information. Installation on AIX ------------------- If you already have a previous version of SOM installed, we strongly recommend that you install SOM 3.0 in a new directory rather than copying over the contents of the previous SOM directory. Installation instructions should be executed as root user. 1. Copy the SOMobjects Developer Toolkit for AIX tar file, som30aix.tar.Z, to the directory where you wish to install SOM 3.0. If this is a first time install, make a directory called /usr/lpp/som and copy the tar file to this directory. If you already have a previous version of SOM installed, make a directory called /usr/lpp/som30, and copy the som30aix.tar.Z to this directory. The following instructions will assume an install directory of /usr/lpp/som. Uncompress and then untar the file with the following commands: uncompress som30aix.tar.Z tar -xvf som30aix.tar 2. Execute one of the supplied shell scripts in the /usr/lpp/som/bin directory, somenv.sh or somenv.csh, to initialize basic SOM environment variables. By default, these scripts assume SOM has been installed in /usr/lpp/som. If you have installed SOM in another directory, edit the appropriate script and modify the value of SOMBASE to the directory where you installed SOM 3.0. cd /usr/lpp/som/bin . ./somenv.sh (for Korn shell) source ./somenv.csh (for C Shell) You may want to incorporate these scripts into your .profile (Korn shell) or .login (C shell). 3. The irindex command builds indexes for the Interface Repository files. A one-time synchronization must be performed at install time. Issue the following command: irindex $SOMBASE/etc/som.ir There is no output from the irindex program if it is successful. 4. Configure DSOM Prior to configuring DSOM, make sure that if the SOMIR environment variable is set, that it is a valid setting. Configuring Install Hosts - Edit the /usr/lpp/som/etc/somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Save the revised somenv.ini file. - Run "som_cfg -i" to configure the Install host. - If you are going to continue by configuring some DSOM hosts on other machines, leave SOMDD running on the Install host. Otherwise, stop somdd with a system "kill" command on the somdd process ID. Configuring DSOM Hosts - Copy the GLOBAL_OBJREF_FILE from the install host to the DSOM host. The default file name of the GLOBAL_OBJREF_FILE is somnm.ref. and is in the /usr/lpp/som/etc/dsom directory on the Install host. We suggest copying it to the /usr/lpp/som/etc directory on the DSOM host. Do not copy it to the /usr/lpp/som/etc/dsom directory, as the som_cfg program needs an empty /usr/lpp/som/etc/dsom directory. - Edit the /usr/lpp/som/etc/somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Change the GLOBAL_OBJREF_FILE value in the DSOM host's somenv.ini file to "$SOMBASE/etc/somnm.ref". - Make sure somdd is running on the Install Host. - Run "som_cfg -d" to configure the DSOM host. - Stop the DSOM host somdd with a system "kill" command on the somdd process ID. Configuring Simple DSOM clients (cannot run DSOM servers) - Edit the /usr/lpp/som/etc/somenv.ini file Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Copy the SOMNMOBJREF value from the install host's somenv.ini to the DSOM client's somenv.ini. - som_cfg does not need to be run for simple DSOM clients. You are done. 5. Build the SOM binding header files. To build the SOM binding files for C and C++, do the following: - For C header files such that object type variables do not need an '*', run somcorba. - For C header files such that object type variables do need an '*', run somstars. - For C++ header files, run somxh. 6. See Chapter 2 of the Programmer's Guide, Volume 1: SOM and DSOM for additional configuration information. Installation on OS/2 -------------------- If you already have a previous version of SOM installed, we strongly recommend that you install SOM 3.0 in a new directory rather than copying over the contents of the previous SOM directory. This is especially true if you have installed the SOM 3.0 OS/2 Beta. 1. Copy the zip file, som30os2.zip, or the Internet-sized OS/2 zip files, som30ox1.zip, som30ox2.zip and som30ox3.zip, to the directory where you wish to install SOM 3.0. If this is a first-time install, make a new root directory called som, and copy the zip file(s) there. If you have a prior version of SOM installed on your machine, create a new directory for SOM 3.0 and copy the SOMobjects Developer Toolkit for OS/2 zip file(s), to this directory. The following instructions will assume an install directory of c:\som. 2. If you must install over a previous version of SOM, disable the Workplace Shell before unzipping the zip file(s). There are two ways to do this: A. Modifying config.sys to boot OS/2 in non-Workplace Shell mode. - Modify the config.sys LIBPATH statement so that the c:\som\lib directory where you are installing SOM 3.0 appears first in the list of directories in each of these statements. This will allow Workplace Shell to pick up the new SOM 3.0 dlls. - Make a temporary backup copy of this new config.sys. Call it config.som. - Again, edit config.sys and modify the PROTSHELL statement and the RUNWORKPLACE statements. Change the PROTSHELL statement to: PROTSHELL=c:\os2\cmd.exe Change the RUNWORKPLACE statement to: SET RUNWORKPLACE=c:\os2\cmd.exe - Reboot the system. OS/2 will boot up in non-WPS mode. - Change to the directory where you copied the zip file(s), and unzip the zip file(s) using your favorite unzip utility. You may use any unzip utility that you like, but make sure you restore the directory structure when unzipping. ex) pkunzip -d som30os2.zip - Copy the backup config.som back to config.sys. - Reboot the system. The OS/2 Workplace Shell will pick up the new SOM 3.0 DLLs. B. Interrupting the OS/2 boot sequence with Ctrl-Alt-F1. - Reboot the system. - When "OS/2" appears in the upper-left-hand corner of the screen, press ctrl-alt-F1 (all three keys at the same time). to bring up the "Recovery Choices" menu. Enter "c" to open an OS/2 full screen window. - Change to the directory where you copied the zip file(s), and unzip the zip file(s) using your favorite unzip utility. You may use any unzip utility that you like, but make sure you restore the directory structure when unzipping. ex) pkunzip -d som30os2.zip - Edit config.sys and add %SOMBASE%\lib to the beginning of the LIBPATH variable. This will allow Workplace Shell to pick up the new SOM dlls. - Press ctrl-alt-del to reboot your system. The OS/2 Workplace Shell will pick up the new SOM 3.0 DLLs. 3. Execute the supplied command file, c:\som\bin\somenv.cmd, to initialize basic SOM environment variables. You must first edit this command file and set SOMBASE to the directory where SOM is installed. cd som\bin (edit somenv.cmd and set SOMBASE to the directory where you installed SOM 3.0) somenv.cmd You may want to incorporate the commands in this command file into your config.sys file so that you do not have to execute this command file whenever you run SOM 3.0 applications. 4. The irindex command builds indexes for the Interface Repository files. A one-time synchronization must be performed at install time. Issue the following command: irindex %sombase%\etc\som.ir There is no output from the irindex program if it is successful. 5. Configure DSOM Prior to configuring DSOM, make sure that if the SOMIR environment variable is set, that it is a valid setting. Configuring Install Hosts - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Save the revised somenv.ini file. - Run "som_cfg -i" to configure the Install host. - If you are going to continue by configuring some DSOM hosts on other machines, leave SOMDD running on the Install host. Otherwise, stop somdd by going to the SOMDD window and pressing ctrl-break. Configuring DSOM Hosts - Copy the GLOBAL_OBJREF_FILE from the install host to the DSOM host. The default file name of the GLOBAL_OBJREF_FILE is somnm.ref. and is in the c:\som\etc\dsom directory on the Install host. We suggest copying it to the c:\som\etc directory on the DSOM host. Do not copy it to the c:\som\etc\dsom directory, as the som_cfg program needs an empty c:\som\etc\dsom directory. - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Change the GLOBAL_OBJREF_FILE value in the DSOM host's somenv.ini file to "c:\som\etc\somnm.ref". - Make sure somdd is running on the Install Host. - Run "som_cfg -d" to configure the DSOM host. - After running som_cfg, stop somdd by going to the SOMDD window and pressing ctrl-break. Configuring Simple DSOM clients (cannot run DSOM servers) - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Copy the SOMNMOBJREF value from the install host's somenv.ini to the DSOM client's somenv.ini. - Som_cfg does not need to be run for simple DSOM clients. You are done. 6. Build the SOM binding header files. To build the SOM binding files for C and C++, do the following: - For C header files such that object type variables do not need an '*', run somcorba. - For C header files such that object type variables need an '*', run somstars. - For C++ header files, run somxh. 7. See Chapter 2 of the Programmer's Guide, Volume 1: SOM and DSOM for additional configuration information. Installation on Windows NT -------------------------- If you already have a previous version of SOM installed, we strongly recommend that you install SOM 3.0 in a new directory rather than copying over the contents of the previous SOM directory. 1. Copy the zip file, som30nt.zip, or the Internet-sized NT zip files, som30nx1.zip, som30nx2.zip and som30nx3.zip, to the directory where you wish to install SOM 3.0. If this is a first-time install, make a new root directory called som, and copy the zip file(s) there. If you have a prior version of SOM installed on your machine, create a new directory for SOM 3.0 and copy the SOMobjects Developer Toolkit for NT zip file(s), to this directory. Unzip the zip file(s) using your favorite unzip utility. You may use any unzip utility that you like, but make sure you restore the directory structure when unzipping. ex) pkunzip -d som30nt.zip The following instructions assume an install directory of c:\som. Note: SOM dynamically links with the C runtime. The SOMobjects Developer Toolkit for NT ships somws35i.dll and somwm35i.dll, the single and multi-threaded C runtime libraries, to avoid requiring VisualAge C++. 2. Execute the supplied command file, c:\som\bin\somenv.cmd, to initialize basic SOM environment variables. You must first edit the command file and set SOMBASE to the directory where SOM is installed. cd som\bin (edit somenv.cmd and set SOMBASE and save the file) somenv.cmd You may want to add these environment variable settings to the System or User Environment Variables in the System settings panel. 3. The irindex command builds indexes for the Interface Repository files. A one-time synchronization must be performed at install time. Issue the following command: irindex %sombase%\etc\som.ir There is no output from the irindex program if it is successful. 4. Configure DSOM Prior to configuring DSOM, make sure that if the SOMIR environment variable is set, that it is a valid setting. Configuring Install Hosts - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Save the revised somenv.ini file. - Run "som_cfg -i" to configure the Install host. - If you are going to continue by configuring some DSOM hosts on other machines, leave SOMDD running on the Install host. Otherwise, stop somdd by going to the SOMDD window and pressing ctrl-break. Configuring DSOM Hosts - Copy the GLOBAL_OBJREF_FILE from the install host to the DSOM host. The default file name of the GLOBAL_OBJREF_FILE is somnm.ref. and is in the c:\som\etc\dsom directory on the Install host. We suggest copying it to the c:\som\etc directory on the DSOM host. Do not copy it to the c:\som\etc\dsom directory, as the som_cfg program needs an empty c:\som\etc\dsom directory. - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Change the GLOBAL_OBJREF_FILE value in the DSOM host's somenv.ini file to "somnm.ref". - Make sure somdd is running on the Install Host. - Run "som_cfg -d" to configure the DSOM host. - After running som_cfg, stop somdd by going to the SOMDD window and pressing ctrl-break. Configuring Simple DSOM clients (cannot run DSOM servers) - Edit the c:\som\etc\somenv.ini file. Change all occurences of "thehostname" to the machine's TCP/IP hostname. If you intend to run DSOM across machines, change "SOMDPROTOCOLS=SOMD_IPC" to "SOMDPROTOCOLS=SOMD_TCPIP". Copy the SOMNMOBJREF value from the install host's somenv.ini to the DSOM client's somenv.ini. - som_cfg does not need to be run for simple DSOM clients. You are done. 5. Build the SOM binding header files. To build the SOM binding files for C and C++, do the following: - For C header files such that object type variables do not need an '*', run somcorba. - For C header files such that object type variables need an '*', run somstars. - For C++ header files, run somxh. 6. See Chapter 2 of the Programmer's Guide, Volume 1: SOM and DSOM for additional configuration information. ISO Latin-1 Code Page Conversion -------------------------------- DSOM 3.0 supports a configuration file setting, SOMDISOLATIN1, in the [somd] stanza of somenv.ini, which, if set to 1, instructs DSOM to convert to the ISO Latin-1 codeset (ISO8859-1 or IBM-819) character data in messages sent between processes. This support is provided for two reasons: (1) to allow interoperability between ASCII-based systems (AIX, OS/2, NT) and EBCDIC-based systems (MVS). (2) to comply with the CORBA 2.0 IIOP interoperability specification. (Note, however, that most non-IBM ORBs do not yet perform translation for character data in messages, therefore setting SOMDISOLATIN1 may actually hinder interoperability between DSOM 3.0 and other vendors' ORBs.) Applications requiring interoperability with SOMobjects on MVS should set SOMDISOLATIN1=1 in the [somd] stanza of the SOMobjects configuration file. Most other users will probably want to leave it unset, to enhance performance and to allow interoperability between SOMobjects 3.0 and non-IBM ORBs. Note that on OS/2 and Windows NT, ISO Latin-1 code set conversion of character data, using the SOMDISOLATIN1 setting, is only supported for systems/applications using the IBM-850 or IBM-437 code sets (which is the case for most English systems). OS/2 and Windows NT users who wish to enable ISO Latin-1 code set conversion who don't have the VisualAge C++ compiler installed: it is necessary to download file localeo2.zip (for OS/2) or localent.zip (for Windows NT) from the SOMobjects Developer Toolkit Web page. Unzip the file and update the LOCPATH environment variable in your operating system environment to include the directory created by unzipping it. Updated Component Information ============================= General Component Information ----------------------------- The following items affect either the product as a whole or multiple components. 1. Applications written with SOMobjects 2.x may need to increase the application stack size when migrating to SOMobjects 3.0. 2. Applications written for Windows NT should use the Gd+ compile option. Gd is a compiler option which specifies whether to dynamically or statically link with the VAC++ runtime functions. Gd+ indicates dynamic linking. 3. When using the def emitter on Windows NT, update the output .nid file to export "_SOMInitModule@12". This is required when using module names within IDL files. 4. Scripts or processes checking the return code from an application running on Windows NT may not receive an accurate value. Although main may return 0 indicating success, another value may be received by the caller. 5. som_cfg creates error log entries that can be ignored if som_cfg completes successfully. You can expect log entries with the following error codes: Error code is 30109 [SOMDERROR_SOMDDNotRunning]. som_cfg starts the DSOM daemon if it is not running. When querying for the status of the daemon, this error may be raised. Error code is 30046 [SOMDERROR_EntryNotFound]. som_cfg registers the Naming Service and Security Service in the Implementation Repository. When querying whether entries for these servers already exist, this error may be raised. Error code is 30088 [SOMDERROR_NamingNotActive]. When registering with the Implementation Repository, DSOM will attempt to store the information in the Naming Service. If the Naming Server is not running, this error will be raised. 6. DSOM and the Object Services do not provide code page conversion. Therefore, if a client and server are operating under different code pages, operations performed against character data will have unpredictable results. 7. On AIX, an application must call SOMD_Init before invoking a method migrated from SOMDObject to SOMObject. This requirement applies to the following methods: create_request, create_request_args, duplicate, get_implementation, get_interface, is_nil, is_proxy, and release. 8. SOMobjects 3.0 does not support Direct-To-SOM. The following notes are provided to assist users who created DTS C++ code using support provided by earlier releases, and who now want to migrate this DTS C++ code to C or native mode C++ code that uses the C or native mode C++ bindings provided by the SOMobjects 3.0 product. DTS C++ allows definition and use of either native mode or SOM classes, but the following discussion focuses on DTS C++ code that implements or uses SOM classes. There are a few different usage scenarios for DTS C++: 1) To implement SOM classes: a) start with IDL, use the hh emitter to produce a DTS C++ header, include this header into a DTS C++ implementation file that you write. b) start with DTS C++. Optionally, use the DTS C++ compiler to produce IDL for other users. 2) To use SOM classes: a) if the SOM classes are described using IDL, use the hh emitter to produce a DTS C++ header, include this header into your DTS C++ source file. b) if the SOM classes are described using a DTS C++ header, include this header into your DTS C++ source file. The migration issues related to each of the above scenarios are somewhat different: 1a) Generate new usage bindings, implementation bindings, and implementation template from the IDL that was originally used as input to the hh emitter. In general, for each member function definition in your DTS C++ implementation source, your implementation template file will contain a global function stub. You'll need to move the code from your member function definitions to the function stubs in the template file. Expect to make lots of changes in the source code. You'll have to rewrite any use of stack-allocated objects to use heap allocation. And, of course, access to instance variables is done differently in the native mode bindings (via somThis). 1b) The IDL provided by the DTS C++ compiler will likely require modifications. After you have made any necessary modifications, proceed as in case 1a. 2a) DTS C++ code that uses SOM objects (as opposed to implementing them) should generally port fairly easily to native mode C++ usage bindings. The big exception is stack-allocated objects. 2b) Again, as in case 2a, it will be necessary to produce IDL from which usage bindings can be generated. SOM Kernel ---------- 1. The somthrd.h file is no longer available. Replace each of the following functions: Old Function Replacement Function on OS/2 ---------------------------------------------------- SOMStartThread() _beginthread() SOMEndThread() _endthread() SOMKillThread() DOSKillThread() SOMYieldThread() DOSSleep(0) SOMGetThreadHandle() DOSGetInfoBlocks() Similar functions are also available on AIX and Window NT. For more information, see the programming guide for your operating system. The following typedefs are no longer supported. somTD_SOMStartThread somTD_SOMEndThread somTD_SOMYieldThread somTD_SOMKillThread() somTD_SOMGetThreadHandle 2. The SOMObject methods somDispatchV, somDispatchL, somDispatchA, and somDispatchD have been replaced by the single SOMObject method somDispatch. 3. The generated class name for a derived metaclasses is now of the form SOMM_<class>_Derived. In 2.x, the class name was of the form M_<class>_Derived. SOM Emitters ------------ 1. Usage bindings now support IDL files that contain only global definitions. As before, global definitions must be bracketed within somemittypes on/off pragmas to emit the corresponding bindings. 2. When a typedef within one IDL file refers to a type defined in some other IDL file, the emitted usage bindings for the first IDL file will automatically #include usage bindings corresponding to the other IDL just prior to the typedef mapping. This side-effect of typedefs allows you to use typedefs to assure that headers upon which usage bindings for your IDL depend will be #included into the usage bindings for your IDL, while avoiding the use of passthru statements. There is no similar support for types that simply appear in method signatures. If you define a method that uses a type defined in some other IDL file, and usage bindings for that other file will not be included for some other reason, you should add a typedef to your interface that mentions a type defined in the other IDL file. 3. The fix for mapping interface typedefs into usage bindings that was originally provided in CSD212 (via the sc command line modifier -mitdfix) is now the default behavior. As a result of this fix, the IDL typedef typedef I myType; // where I is an interface results in usage bindings that include the following typedef: typedef I myType; Thus, in all cases, the name myType must be treated (by bindings and program code) in the same way that the name "I" would be treated. Because of the way that previous bindings mapped interface typedefs (by adding an explicit star to the typedef in some cases), two kinds of source changes may be required when recompiling code that uses non-CORBA C bindings: a. The prototypes for methods that receive myType arguments must be changed. Compile-time errors when compiling class implementations would signal this, and the simplest response is to use the incremental template emitter to modify the method procedure prototypes. It should not be necessary to make these changes in your method implementations by hand. The template emitter will make the necessary changes in the signatures of your method procedures. b. Code that uses local variables of type myType may have to be modified by hand, by adding a star (when using the non-CORBA somstars C bindings). In this release, the older mapping for typedefs may be generated by using the sc command line modifier -mitdlegacy but their continued use is not recommended. 4. The following enhancements to initializers have been made: a. New control argument types have been declared in somobj.idl. These have the same structure as the original types, but are passed as "in" parameters to initializer methods instead of "inout" parameters. This change does not affect the C and C++ bindings, but is important to Smalltalk bindings. The names of the new control types differ from those used previously because they start with "som3" instead of "som". Thus, for example, there is a new type named som3InitCtrl. The old names are still supported (they are defined in somapi.h, along with the new ones). So, there is no reason to modify existing C or C++ code to use the new type names, but you may want to modify the IDL for your classes if you want Smalltalk code to be able to invoke initializers on their instances. To do this, add a "3" to the initial "som" in the control argument type for your initializers, and change "inout" to "in" for this argument. All the methods in SOMObject that take control arguments, and output from the template emitter use the new type names. When you define new classes in IDL, their initializers should use the new type names. b. Initializers can now be overridden. That is, a class can define a local initialization method by overriding an inherited initializer. You need to specify the init modifier along with the override. For example, if foo is an inherited initializer method, the following could be used in the implementation section to override it: foo: override, init; This results in an initializer template in your emitted implementation template file, and usage bindings for your class will include a constructor that invokes foo. c. When the implementation template for overrides of SOMObject's object copy and object assignment methods is emitted, the ancestor calls that are provided correspond to the method that is overridden. For example, if you override somDefaultConstVCopyInit, then ancestor calls to somDefaultConstVCopyInit will be emitted in the implementation template file. But, when the macros that support ancestor calls to SOM's object copy and object assignment methods are emitted in implementation bindings, macros are provided only for those methods that are actually available in the ancestor. A comment in the implementation bindings indicates when one of these methods is not available in an ancestor. The concept of copy and assignment method availability is new to SOMobjects 3.0. It works as follows: a copy or assignment method is available in a class if: - It is defined by the class (by overriding the method) - The method is "below" a stronger method that is defined - The method is somDefaultCopyInit or somDefaultAssign. Here are the strength orderings for SOMObject's copy methods. A similar diagram describes the corresponding assignment methods. somDefaultConstVCopyInit / \ / \ / \ / \ somDefaultConstCopyInit somDefaultVCopyInit \ / \ / \ / \ / somDefaultCopyInit For example, if a class X defines somDefaultConstInit, ancestor initializer macros in a subclass will be provided (only) for somDefaultConstInit and somDefaultInit. So, if you subclass this class to create Y and override somDefaultVCopyInit (for example), you will have the following unresolved symbol when you try to link your class implementation: Y_Init_X_somDefaultConstVCopyInit This tells you that somDefaultConstVCopyInit is not available in X. You would then look at X's IDL (or at your implementation bindings) to see what object copy methods are available in X, and use those instead. As mentioned above, somDefaultCopyInit will always be available. 6. A new chk emitter checks that the IDL input to the SOM compiler is semantically meaningful, to guarantee that output from all other emitters will be useful. This emitter does not create an output file. Normally, the chk emitter is run automatically before other emitters (you can see this by using the -v switch when using the sc command to invoke an emitter explicitly). But, you can also invoke the chk emitter explicitly as with any other emitter (by using -schk on the sc command line), or you can omit its execution by using -mnochk on the sc command line. Many of the checks performed by the chk emitter are obvious. One of the new checks is that all interfaces other than SOMObject must specify a parent which guarantees useful .xh bindings. This is a new requirement. The chk emitter generates warnings for any unsupported modifiers. * Modifiers related to attributes can sometimes cause spurious warnings, for example: my_attribute: nodata; This may raise two warnings: Once for "nodata" and once for "my_attribute" under certain conditions. The warning looks like this: "<file-name>", line <line-no>: warning: Unknown modifier "my_attribute" in interface/method "<interface-name>". It may be misspelled. 7. The PDL program now supports more sophisticated processing of IDL files. In previous versions of the toolkit, PDL could remove only sections of IDL text bracketed via #ifdef and #endif directives. PDL is now also capable of removing sections delimited via #if and #ifndef directives, and partially evaluating conditional expressions. See the Programmer's Guide Volume I for details. 8. The following Emitter Framework typedefs/functions have been renamed: old new --------------------------------------------------- EmitFn EmitFnSL somterror somterrorSL somtfatal somtfatalSL somtfclose somtfcloseSL somtinternal somtinternalSL somtmsg somtmsgSL somtopenEmitFile somtopenEmitFileSL somtresetEmitSignals somtresetEmitSignalsSL somtunsetEmitSignals somtunsetEmitSignalsSL somtwarn somtwarnSL Under SOM2.1, the above functions/typedefs did not make use of SOMLINK. This worked on AIX, but is not particularly portable on OS/2 and NT. For backward compatibility, the old functions/typedefs are still available. However, use the new functions for portability. 9. When a SOMFOREIGN type is referenced in an IDL method declaration, the emitters generate incorrect bindings for the method in the following situation: 1. the SOMFOREIGN type is declared in the same interface as the method that references it 2. the SOMFOREIGN type has the "struct" storage class as indicated by the "struct" IDL modifier 3. the "struct" modifier for the SOMFOREIGN type is specified using a SOM IDL modifier statement (in the implementation section) rather than using the modifier #pragma. The workaround is to use the modifier #pragma instead of the modifier statement, for SOMFOREIGN types that need to be referenced in method declarations prior to the implementation statement. Distributed SOM (DSOM) ---------------------- Important differences between DSOM 2.1 and DSOM 3.0 --------------------------------------------------- Configuration (regimpl and the Implementation Repository) --------------------------------------------------------- DSOM runtime settings must now come from the [somd] stanza in the configuration file, and from environment variables. (The configuration file name is specified by the SOMENV environment variable.) SOMIR, HOSTNAME, and USER are still supported as environment variables. If these environment variables are unset, the configuration file is consulted. Compile-time environment variables (those used by the SOM Compiler and Emitters) are also not affected. Registering servers (using regimpl) requires that somdd is running and that the Naming Service has been configured using the som_cfg tool because DSOM now uses the Naming Service to store server-class associations. There are other significant changes to the Implementation Repository; see the Programmer's Guide Volume 1 for more information. DSOM doesn't support outstanding object references when a server machine is upgraded from one version of DSOM to another. This implies that "object reference table" files are rendered obsolete during the upgrade. Error Handling -------------- DSOM 3.0 almost never terminates the process in which it is run because of a DSOM exception. This allows applications to control when they terminate and how they cleanup. It also means that applications are responsible for error checking after every DSOM call. Applications should avoid, however, checking for specific DSOM minor codes, because these are subject to change. User exceptions raised by remote method invocations cannot be marshaled unless the method declares the exception in a "raises" expression in IDL. Otherwise, DSOM returns a system exception to the client (with minor code SOMDERROR_UndeclaredException). System exceptions can be raised by any method and are not declared in an IDL "raises" expression. Sockets Classes --------------- User-defined Sockets classes are no longer supported. Configuration has been simplified by eliminating the SOMSOCKETS environment variable. One exception is that SOMSOCKETS is used by migimpl3, a tool to convert 2.1 Implementation Repositories to 3.0 format. SOMSOCKETS is used by migimpl3 to determine what value of SOMDPROTOCOLS to assume for the converted entries. Parameter Memory Management --------------------------- In DSOM 2.x, the default parameter-memory management policy was not uniformly "caller owns". (The "memory_management=corba" IDL modifier had to be used to request this behavior.) Applications that are recompiled using DSOM 3.0 will have a new default policy, which is "caller owned". If this new default is not appropriate for the application, then the application's IDL should be modified to contain explicit modifiers (for example, object_owns_result, object_owns_parameters, dual_owned_result, dual_owned_parameters, and suppress_inout_free). See the Programmer's Guide Volume I for more information. The new memory-management policy does not affect an application until its .ih/.xih files are regenerated using the SOMObjects 3.0 SOM Compiler. For some data types, the storage inside an inout parameter will be unconditionally freed in the "in" direction, and reallocated in the "out" direction (in the client's address space), when using the default parameter-memory management policy. Specifically, an inout object reference, the _value and _type fields of an inout any, an inout TypeCode, and inout SOMFOREIGNS have this property. Thus, this storage must be allocated with SOMMalloc, and may not be static or automatic storage. For inout strings, sequences, and pointers, the "in" storage may be freed and reallocated by DSOM if it changes in the "out" direction. Specifically: - if an unbounded string comes back longer than the original, or set to NULL, the original will be freed by DSOM, - if an unbounded sequence's _buffer comes back longer than the original's _maximum, the original is freed and reallocated by DSOM, - if a pointer comes back NULL, then the original value is freed by DSOM. Thus, even though it is legal for inouts of these types to point to static storage, it is risky, because it relies on the out value not invalidating the original storage. When an application object changes an inout parameter (for example, giving a string a longer value) in a way that causes storage to be "orphaned", the object is responsible for freeing the orphaned storage (for example, the old string), unless the method parameter has the IDL modifier "suppress_inout_free". The argument to ORBfree in DSOM 3.0 is the topmost argument pointer used to return a result or out parameter. (In DSOM 2.x, the argument to ORBfree was the topmost "freeable" pointers within the parameter.) This allows an application to free all ORB-allocated memory in a return result or out parameter with a single call, rather than multiple calls. As in DSOM 2.x, ORBfree frees only the memory within the parameter that the ORB allocated on behalf of the client (and not any memory within the parameter that the application allocated). ORBfree is not applicable to inout parameters or exceptions parameters. In DSOM 3.0, it is an error for an application object (within a server) to dereference an out parameter of type pointer. Like all other out parameters, the initial value must be set by the application object, and the object should not assume that the initial value of an out parameter is valid data. Object Reference Table ---------------------- Support for the Object Reference Table, including the SOMOA methods create_constant and change_id, is now deprecated. create_constant is now equivalent to create except for servers whose ImplementationDef object specifies an Object Reference Table file name. If a file name is specified, the 2.x semantics of create apply. Object Reference Table data will be stored in the directory designed by SOMDDIR (as opposed to the Object Reference Table file name specified in the ImplementationDef). The same files can be used by multiple servers. Servers that need persistent storage of object-reference data, such as that previously provided by the Object Reference Table, should implement this functionality in an application- pecific subclass of SOMDServer or use the SOMOS::Server class. New Method Semantics -------------------- DSOM applications, once recompiled, will receive the new default behavior for invoking somFree on a proxy object. The new behavior is that both the remote object and the proxy are freed. (The 2.x default was that only the remote object was freed.) Applications that want to continue to use the 2.x default behavior for somFree must set the somd21somFree attribute of the SOMD_ObjectMgr global object to FALSE after calling SOMD_Init. This attribute, however, is deprecated and may not be supported in future releases. DSOM applications, once recompiled, will receive the new default behavior for the ORB::string_to_object method. The new behavior is that if the string object reference refers to an object local to a server, the local SOMObject will be returned, rather than a SOMDObject. (The 2.x behavior was to return a SOMDObject, which is not local/remote transparent.) Applications that want to continue to use the 2.x default behavior for string_to_object must set the stringToObject30 attribute of the SOMD_ORBObject global object to FALSE after calling SOMD_Init. This attribute, however, is deprecated and may not be supported in future releases. Known restrictions in DSOM -------------------------- 1. For machines that are used together as a DSOM workgroup (where the DSOM client is run on one machine and the DSOM server is run on another machine), both machines must be running the same version of SOMobjects (either 2.x or 3.0 GA). A machine running SOMobjects 2.x will not communicate via DSOM with a machine running SOMobjects 3.0. 2. SOMObject methods get_implementation and get_interface are not supported when executed between DSOM and another ORB. 3. User-defined proxy classes and user-defined proxy base classes developed using SOMobjects 2.x are incompatible with SOMobjects 3.0. Such proxy classes must be reimplemented using a new programming model; see the Programmer's Guide Volume I for more information. 4. When classes are registered in the Naming Service (for example via regimpl), to be retrieved by client applications using the DSOM Factory Service, the Naming Server running on the install host must be able to load those classes. This means that the DLLs for those classes must be loadable by the install host's Naming Server (either the real DLL or a "stub" DLL), and if the class name is not the same as the DLL name, the install host Naming Server's SOMIR setting must reference an Interface Repository file that contains the classes' "dllname" modifiers. 5. There are known problems restarting the Workplace Shell DSOM server thread. After running an application and terminating the server thread, a system reboot is necessary before the server can be restarted. As a result, when running the Sample DSOM Client shown in the Workplace Shell Programming Guide (or any DSOM WPS client program that starts/stops the daemon and server programmatically if they are not already running), it is advisable to start the daemon and server using the "wpdsinit /s" command before running the client. This prevents the client from terminating the server, allowing the client to be rerun any number of times without rebooting. It also insures that the daemon will be ready before the client attempts to make the first remote request. 6. On AIX, if a DSOM process terminates without calling SOMD_Uninit, the resources often remain allocated. The cleanipc script can be used to free IPC resources for a particular user. Due to potential side effects, cleanipc does not free resources when run as root. Consider using a privileged user id other than root to run the DSOM daemon and application servers. Another disadvantage to running the DSOM daemon as root is that servers started by the daemon will also execute as root; this adds a potential security exposure to the system. 7. If your application runs for an extended period of time, it is recommended that you set SOMDNUMTHREADS in the [somd] stanza of somenv.ini. SOMDNUMTHREADS specifies the maximum number of request threads created per server. Object Services --------------- 1. When deriving classes from somOS::ServiceBase and overriding the method init_for_object_reactivation, do not perform any actions within the implementation of init_for_object_reactivation that will result in a remote method invocation on another server. When a server is performing init_for_object_reactivation, it cannot perform any remote communication; if any is attempted, the server will hang. 2. The Security Service should be used with servers that use somOS::Server (such as somossvr.exe); when used with other servers (such as somdsvr.exe), errors may occur when the server is terminating. 3. When using the Security Service, if the server's entry in the Implementation Repository initially indicates that the server is secure, then is changed to indicate that the server is not secure, the server will continue to behave as a secure server. The workaround is to unregister the server from the Implementation Repository and re-register the server as a non-secure server (so that the server will have a new UUID). 4. The Externalization Service is not thread safe. Trademarks ========== AIX is a trademark of International Business Machines Corporation. IBM is a trademark of International Business Machines Corporation. OS/2 is a trademark of International Business Machines Corporation. SOM is a trademark of International Business Machines Corporation. SOMobjects is a trademark of International Business Machines Corporation. VisualAge C++ is a trademark of International Business Machines Corporation. C Set++ is a trademark of International Business Machines Corporation. Windows is a trademark of Microsoft Corporation. Windows NT is a trademark of Microsoft Corporation. Your Satisfaction ================= Your satisfaction is important to us. If you encounter a problem you believe to be a defect in the SOMobjects Developer Toolkit code or documentation, please submit a report to the technical support team. The problem submission form is located at: http://www.austin.ibm.com/somservice/supform.html SOMobjects, Making Reuse a Reality
 hobbes.nmsu.edu/download/pub/os2/dev/wps/som30os2.zip  local copy
IDL/Java Language Mapping (23/12/1996, International Business Machines Corporation (IBM)) Readme/What's new
IBM SOMobjects Java Client README file -------------------------------------- (C) COPYRIGHT International Business Machines Corp. 1996 All Rights Reserved Licensed Materials - Property of IBM US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. Java is a trademark of Sun Microsystems, Inc. Windows NT is a trademark of Microsoft Corp. AIX, OS/2 and SOMobjects are trademarks of IBM Corp. Thank you for your interest in the SOMobjects Java Client. INSTALLATION STEPS ON SERVER MACHINE ==================================== 1. Place the som30jcl.zip (OS/2, NT) or som30jcl.tar.Z (AIX) file in a directory in your web server's HTML directory structure. For example, x:\www\html\sjclient on OS/2 and NT, or /usr/lpp/www/html/sjclient on AIX. The exact location will depend on how you have your web server directories organized. If you intend to use the Java client files installed directly on the client machine rather than have them downloaded from a web server, you can place the zip or tar file in any convenient directory. (You'll also need to update your CLASSPATH environment variable to point to this directory as well.) 2. Unpack the zip or tar file. It will create subdirectories as it unzips. unzip som30jcl.zip (OS/2 and NT) tar -xvZf som30jcl.tar.Z (AIX) 3. See the file Setup.html for a continuation of the setup procedures. PROBLEM REPORTING ================= Your satisfaction is important to us. If you encounter a problem you believe to be a defect in the SOMobjects Developer Toolkit code or documentation, please submit a report to the technical support team. The problem submission form is located at: http://www.austin.ibm.com/somservice/supform.html FEEDBACK ======== We would like to know what you think about this product - you can send feedback to me personally. My internet address is: rschnier@vnet.ibm.com. This address is only for feedback: - do you like it? - do you hate it? - should it be more? - should it be less? - what would you like to see it do in the future? For problems and bug reports, please use the normal SOM 3.0 support channels described above. Please *do not* send bug reports or configuration questions to my e-mail address - we have a separate service group set up for these types of issues. Your cooperation and understanding are greatly appreciated. I will read all mail, but cannot promise a response to all inquiries or suggestions. And thanks again for giving our stuff a try! We think it's pretty cool, and hope you will too. Regards, The IBM SOMobjects Java Client Development Team: Randy Schnier, Russell Butek, Joe Bockhold, Tony Bachand, Kim Cink
 hobbes.nmsu.edu/download/pub/os2/dev/wps/som30jcl.zip  local copy
Class Object in SOM (30/1/1995, Nurcan Coskun, Roger Sessions) Readme/What's new
CLASS OBJECTS IN SOM by Nurcan Coskun and Roger Sessions ----------------------------------------------------- Note: 1. Words inside angle brackets should be computer font. 2. Bold lines are indicated by "<--" in right margin. ----------------------------------------------------- THIS ARTICLE WAS ORIGINALLY PUBLISHED IN THE PERSONAL SYSTEMS DEVELOPER SUMMER 1992 AND IS COPYRIGHT BY IBM. THIS ARTICLE MAY NOT BE REPRINTED IN WHOLE OR IN PART WITHOUT PERMISSION. ABSTRACT This article continues the discussion of SOM begun in the winter issue of the Personal Systems Developer. In this article we look at one of the advanced programming features of SOM: the class object. The class object can be used to retrieve at run time a great deal of useful information about classes, including the name of the class and the methods supported. The class object also knows how to instantiate objects of a given class. We give an overview of the class object, and discuss the concept of metaclass. A metaclass of a given class is the class of that class's class object. We show the two important techniques for changing a class's metaclass. INTRODUCTION In the winter issue of the Personal Systems Developer USessions and Coskun, 92e, we gave an introduction to the System Object Model (SOM). SOM is a new methodology for creating object-oriented class libraries introduced by IBM in OS/2 2.0. In our last article we discussed the basic concepts of object-oriented programming: developing classes and instantiating objects; deriving new classes through inheritance; and resolving methods with polymorphism. We also discussed the primary goals of SOM: multi-language support (including both procedural and object-oriented languages); upwardly compatible binaries; and object-oriented extensions to nonobject- oriented languages. In this article we are going to explore an advanced feature of SOM: the class object. We assume that you are familiar with the introductory concepts of our last article. If you find yourself getting lost here, you should go back and revisit our winter article. GOALS OF SOM SOM is a language neutral mechanism for developing object-oriented class libraries. SOM consists of a run-time repository for class information and a series of language bindings. Pictorially we can describe SOM as shown in Figure 1. ................................................................ Figure 1. SOM Run-Time Class Repository and Language Bindings +-+ +-----+ +-------+ +---+ +---------+ ]C] ]Cobol] ]Fortran] ]C++] ]Smalltalk] +-+ +-----+ +-------+ +---+ +---------+ ] ] ] ] ] V V V V V ... etc +------------------------------------------+ ] SOM Run-Time Class Repository ] +------------------------------------------+ ] ] ] ] ] ... etc V V V V V +-+ +-----+ +-------+ +---+ +---------+ ]C] ]Cobol] ]Fortran] ]C++] ]Smalltalk] +-+ +-----+ +-------+ +---+ +---------+ ................................................................ The box in Figure 1 with C pointing to the Run-Time Repository represents a binding which allows classes to be defined in C and added to the SOM run-time repository. The box from the run-time repository to C is a binding which allows C to use classes from the repository regardless of the language in which the classes were originally written. When we say "use a class", we mean either instantiating and invoking methods on objects of a class, or deriving new classes using that class as a base class. In the current version of OS/2 2.0, we support only the C language bindings. The other languages shown in figure 1 are for illustration only. This is neither a complete list of languages under consideration nor a committed list. We are working with a wide variety of language suppliers, both internally and externally, to make this list as complete as possible. As we discussed in the Winter issue, the C bindings allow object-oriented programs to be developed much like they are developed in C++. However in contrast to C++, SOM allows classes to be used by a wide variety of languages as new language bindings become available. SOM also solves other weaknesses in C++ when it comes to developing class libraries. For a good introduction to C++ and these library issues, see Class Construction in C and C++ USessions, 92e. CLASSES IN SOM Lets reconsider a set of classes we first looked at in the winter issue. We will start with the <Student> class. An object of type <Student> knows how to set up its id and name. It knows how to return its ID. Finally, it knows how to print itself. The class definition file for <Student> is shown in Figure 2. .................................................... Figure 2. <Student> class definition include <somobj.sc> class: Student; parent: SOMObject; data: char idU16e; /* student id */ char nameU32e; /* student name */ methods: override somInit; void setUpStudent(char *id, char *name); void printStudentInfo(); char *getStudentType(); char *getStudentId(); .................................................... The class implementation file for <Student> is shown in Figure 3. Recall from our last article that most of the class implementation file is produced automatically by the SOM compiler. Those lines shown in bold face are the only lines the class implementor actually needs to write. ................................................................ Figure 3. <Student> class implementation (Programmer added lines shown in bold type) #define Student_Class_Source #include "student.ih" SOM_Scope void SOMLINK somInit(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); parent_somInit(somSelf); _idU0e = _nameU0e = '\0'; <-- } SOM_Scope void SOMLINK setUpStudent(Student *somSelf, char *id, char *name) { StudentData *somThis = StudentGetData(somSelf); strcpy(_id, id); <-- strcpy(_name, name); <-- } SOM_Scope void SOMLINK printStudentInfo(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); printf("\n Id : %s \n", _id); <-- printf(" Name : %s \n", _name); <-- printf(" Type : %s \n", _getStudentType(somSelf)); } SOM_Scope char * SOMLINK getStudentType(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); static char *type = "student"; <-- return (type); <-- } SOM_Scope char * SOMLINK getStudentId(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); return (_id); <-- } ................................................................ Given this definition of <Student>, we can derive a new class, say <GraduateStudent>, which is just like a student, but has information about a thesis and a degree. The class definition file for <GraduateStudent> is shown in Figure 4, and the class implementation file is shown in Figure 5. ................................................................ Figure 4. <GraduateStudent> class definition file. include "student.sc" class: GraduateStudent; parent: Student, local; data: char thesisU128e; /* thesis title */ char degreeU16e; /* graduate degree type */ methods: override somInit; override printStudentInfo; override getStudentType; void setUpGraduateStudent(char *id, char *name, char *thesis, char *degree); ................................................................ ................................................................ Figure 5. <GraduateStudent> class implementation file. (Programmer added lines shown in bold type.) #define GraduateStudent_Class_Source #include "graduate.ih" SOM_Scope void SOMLINK somInit(GraduateStudent *somSelf) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); parent_somInit(somSelf); _thesisU0e = _degreeU0e = '\0'; <-- } SOM_Scope void SOMLINK printStudentInfo( GraduateStudent *somSelf) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); parent_printStudentInfo(somSelf); printf(" Thesis : %s \n", _thesis); <-- printf(" Degree : %s \n", _degree); <-- } SOM_Scope char * SOMLINK getStudentType( GraduateStudent *somSelf) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); static char *type = "Graduate"; <-- return (type); <-- } SOM_Scope void SOMLINK setUpGraduateStudent( GraduateStudent *somSelf, char *id, char *name, char *thesis, char *degree) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); _setUpStudent(somSelf,id,name); <-- strcpy(_thesis, thesis); <-- strcpy(_degree, degree); <-- } ................................................................ With these two classes defined and implemented, we can write client code to instantiate and manipulate <Student>s and <GraduateStudent>s. The program shown in Figure 6 instantiates two <Student>s and two <GraduateStudent>s, initializes the objects with data, and asks the objects to print themselves. ................................................................. Figure 6. Client Program For <Student> and <GraduateStudent> Program: #include "graduate.h" main() { Student *student1 = StudentNew(); Student *student2 = StudentNew(); GraduateStudent *grad1 = GraduateStudentNew(); GraduateStudent *grad2 = GraduateStudentNew(); _setUpStudent(student1,"120455","Joe Doe"); _setUpStudent(student2,"103606","Mary Smith"); _setUpGraduateStudent(grad1,"203230","Janet Brown", "Parser Generators", "M.S."); _setUpGraduateStudent(grad2,"240900","Mark Black", "Code Optimization", "Ph.D."); _printStudentInfo(student1); _printStudentInfo(student2); _printStudentInfo(grad1); _printStudentInfo(grad2); } Output: Id : 120455 Name : Joe Doe Type : student Id : 103606 Name : Mary Smith Type : student Id : 203230 Name : Janet Brown Type : Graduate Thesis : Parser Generators Degree : M.S. Id : 240900 Name : Mark Black Type : Graduate Thesis : Code Optimization Degree : Ph.D. ................................................................. CLASS OBJECTS Every class with at least one instantiated object has exactly one associated class object. Every instantiated object maintains a pointer to its class object which it can return through the method <somGetClass>. This method is inherited from <SOMObject>, a class from which every class is derived, either directly or indirectly. In the program shown in Figure 6, <student1> and <student2> are both objects of class <Student>, and therefore both share the same class object. Similarly <grad1> and <grad2> are both objects of class <GraduateStudent>, and therefore both share another class object, different than the class object shared by <student1> and <student2>. This is shown pictorially in Figure 7. .............................................................. Figure 7. Relationship between objects and class objects +--------+ +-----+ ]student1]---> +-------+ +---------------+ <---]grad1] +--------+ ]Student] ]GraduateStudent] +-----+ ]class ] ]class ] +--------+ ]object ] ]object ] +-----+ ]student2]---> +-------+ +---------------+ <---]grad2] +--------+ +-----+ .............................................................. Another way to access a class object is through the SOM defined macro <_classname>. For <Student>, this macro is <_Student>. This macro returns a pointer to the appropriate class object, if it exists, or zero, if it does not exist. SOM instantiates the class object the first time an object of its controlled class is instantiated. The <_Student> will, therefore, return 0 if and only if no <Student> objects have yet been instantiated. The class object is quite a useful object. The class of a class object is either <SOMClass> or, as we will see later, some class derived from <SOMClass>. There are a variety of methods defined for <SOMClass>, and these are all documented in the class definition file for <SOMClass>, <somcls.sc> and described in the SOM documentation USOMe. There are methods which can tell you the size the class, the parent of the class, whether the class is derived from some other class, and whether the class supports a specific method, to name a few. One of the <SOMClass> methods is <somGetName()>, which returns a pointer to a character string containing the name of the class for which this is the class object. For the <Student> class object, this string would be "Student". Another interesting <SOMClass> method is <somNew()>, which returns a newly instantiated object of the appropriate class. For the <Student> class object, the newly instantiated object would be of the <Student> class. The method <somNew()> is always invoked to instantiate new objects. Many programmers are not aware of this because they use a macro wrapper of the form <classnameNew>, for example, <StudentNew()>. This wrapper first makes sure the appropriate class object exists, and then passes through the instantiation request via <somNew()>. In most cases, we would instantiate objects using the class instantiation macro, say <StudentNew()>, but there might be cases when we can access the class object but not the class instantiation macro. One such example might be a function which accepts a pointer to any object, and returns another newly instantiated object of the same class. Figure 8 modifies the client program shown in Figure 6 to make use of the <Student> and <GraduateStudent> class objects and their <somGetClass()> and <somNew()> methods. ......................................................... Figure 8. Client Program Using Class Object #include "graduate.h" SOMAny *createObject(SOMAny *object) { return(_somNew(_somGetClass(object))); } main() { Student *student1 = StudentNew(); GraduateStudent *grad1 = GraduateStudentNew(); Student *student2; GraduateStudent *grad2; student2 = createObject(student1); grad2 = createObject(grad1); _setUpStudent(student1,"120455","Joe Doe"); _setUpStudent(student2,"103606","Mary Smith"); _setUpGraduateStudent(grad1,"203230","Janet Brown", "Parser Generators", "M.S."); _setUpGraduateStudent(grad2,"240900","Mark Black", "Code Optimization", "Ph.D."); _printStudentInfo(student1); _printStudentInfo(student2); _printStudentInfo(grad1); _printStudentInfo(grad2); } ......................................................... Several of the <SOMClass> methods have passthrough methods defined in <SOMObject>. In those cases, the actual code for the passthrough methods just gets the object's class object, and passes through the call using the appropriate <SOMClass> method. For example, the <SOMObject> method <somGetClassName()> passes through to the <SOMClass> method <somGetName()>. In this article we will use either the <SOMObject> methods or the <SOMClass> passthrough, depending on the point we are making. THE CLASS OF THE CLASS OBJECT Every object in SOM is associated with a class. The class of <student> is <Student>, which we can see from this program: #include "student.h" main() { Student *student = StudentNew(); printf("student object is of <%s> class\n", _somGetClassName(student)); } which gives this output: student object is of <Student> class The class objects are also associated with a class. The class of any class object is by default <SOMClass>. The class <SOMClass> is, like all classes, derived from <SOMObject>, and therefore supports all of the <SOMObject> methods. We can, for example, verify the class of the <Student> class object as in the following program #include "student.h" main() { Student *student = StudentNew(); SOMClass *studentClassObject; studentClassObject = _somGetClass(student); printf("student class object is of <%s> class\n", _somGetClassName(studentClassObject)); } giving this output: student class object is of <SOMClass> class We use the word metaclass to describe the class of an objects' class object. Since the class of the student's class object is <SOMClass>, we say the metaclass of <Student> is <SOMClass>. Don't confuse class with metaclass. The class of <student> is <Student>. The metaclass of <student> is <SOMClass>. We can change the metaclass of a given class by a two stage process: 1. Derive a new class from SOMClass, either directly or indirectly. 2. Tell the given class that its class object will be of the new type through the metaclass directive. There are at least three reasons one might want to change the class of a class object. The first is to add new methods for initializing new objects. Such methods are referred to as constructor methods. The second is to modify how memory is allocated for objects. The third is to keep track of global information about the class, such as how many objects have been instantiated. Lets go through the steps necessary to change the class of the <Student> class object from <SOMClass> to <StudentFactory>, or, in other words, changing the metaclass of <student> from <SOMClass> to <Studentfactory>. First, we define the <StudentFactory> to be derived from <SOMClass>. This class will add one new method to those found in <SOMClass>. The new method will be <countObjects()>. We will also override the client invoked <SOMClass> methods <somNew()>, which instantiates a new object. We also need to override the <somInit()> method invoked on a newly instantiated class object, to initialize the count to zero. The class definition and implementation files for <StudentFactory> are shown in Figure 9. ............................................................ Figure 9: Class Definition and Implementation Files for <StudentFactory> Class Definition File: include <somobj.sc> class: StudentFactory; parent: SOMClass; data: int count; methods: override somInit; override somNew; int countObjects(); Class Implementation File: #define StudentFactory_Class_Source #include "countmet.ih" SOM_Scope void SOMLINK somInit(StudentFactory *somSelf) { StudentFactoryData *somThis = StudentFactoryGetData(somSelf); parent_somInit(somSelf); _count = 0; } SOM_Scope SOMAny * SOMLINK somNew(StudentFactory *somSelf) { StudentFactoryData *somThis = StudentFactoryGetData(somSelf); _count ++; return (parent_somNew(somSelf)); } SOM_Scope int SOMLINK countObjects(StudentFactory *somSelf) { StudentFactoryData *somThis = StudentFactoryGetData(somSelf); return (int) _count; } ............................................................ We now modify the student class definition files as shown in Figure 10. ........................................................... Figure 10: Newly Modified student class definition files (Modified lines shown in bold face.) include <somobj.sc> include "countmet.sc" class: Student; metaclass: <-- StudentFactory, local; <-- parent: SOMObject; data: char idU16e; /* student id */ char nameU32e; /* student name */ methods: override somInit; void setUpStudent(char *id, char *name); void printStudentInfo(); char *getStudentType(); char *getStudentId(); .......................................................... No changes are needed to the class implementation file for <Student>. We can now use our new <StudentFactory> object to find out how many student objects have been instantiated, as shown in this program: #include "student.h" main() { Student *student1 = StudentNew(); Student *student2 = StudentNew(); SOMClass *studentClassObject; _setUpStudent(student1,"120455","Joe Doe"); _setUpStudent(student2,"103606","Mary Smith"); studentClassObject = _somGetClass(student1); printf("Student count: %d \n", _countObjects(studentClassObject)); printf("student1 class object is of <%s> class\n", _somGetClassName(studentClassObject)); } giving this output: Student count: 2 student1 class object is of <StudentFactory> class IMPLIED METACLASS Given a new class for class objects, we can have any number of classes associated with the new class object. For example, instead of <StudentFactory> we might have used the metaclass name <CountFactory> to indicate greater generality, and then used this metaclass whenever we want to keep track of total instantiated objects. Often we do not need such generality and we only intend for a given class object to be associated with one class. For example, the only change to the metaclass might be the addition of new constructor methods which are only applicable to a specific class. In such cases we can use a slight short cut to redefine the metaclass. This short cut is called implied metaclass. The main advantage of implied metaclasses is that the class definition file for the metaclass can be folded into the class definition file for the class it controls, and similarly for the class implementation file. The student implementation file rewritten to use the implied metaclass is shown in Figure 11. The student implementation file rewritten to use the implied metaclass is shown in Figure 12. ............................................................. Figure 11. Student Class Definition using implied Metaclass (Changes from original <Student> shown in bold face.) include <somobj.sc> class: Student, classprefix = StudentClass_; <-- parent: SOMObject; data: char idU16e; /* student id */ char nameU32e; /* student name */ int count, class; <-- methods: override somInit; void setUpStudent(char *id, char *name); void printStudentInfo(); char *getStudentType(); char *getStudentId(); override somInit, class; <-- override somNew, class; <-- int countObjects(), class; <-- ............................................................ Notice there are two new keywords used to define implied metaclasses. The keyword "classprefix" indicates a prefix used to identify methods associated with the class object. The keyword "class" is used to identify data members or methods associated with the class object. ............................................................. Figure 12. Student Class Implementation using implied Metaclass (Programmer added lines shown in bold face.) #define Student_Class_Source #include "student.ih" SOM_Scope void SOMLINK somInit(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); parent_somInit(somSelf); _idU0e = _nameU0e = '\0'; <-- } /* Other Student Methods, as before, followed by... */ #undef SOM_CurrentClass #define SOM_CurrentClass SOMMeta SOM_Scope void SOMLINK StudentClass_somInit( M_Student *somSelf) { M_StudentData *somThis = M_StudentGetData(somSelf); parent_somInit(somSelf); _count = 0; <-- } SOM_Scope SOMAny *SOMLINK StudentClass_somNew( M_Student *somSelf) { M_StudentData *somThis = M_StudentGetData(somSelf); _count ++; <-- return (parent_somNew(somSelf)); } SOM_Scope int SOMLINK StudentClass_countObjects( M_Student *somSelf) { M_StudentData *somThis = M_StudentGetData(somSelf); return (int) _count; <-- } ............................................................ Our client program, shown again here, needs no changes: #include "student.h" main() { Student *student1 = StudentNew(); Student *student2 = StudentNew(); SOMClass *studentClassObject; _setUpStudent(student1,"120455","Joe Doe"); _setUpStudent(student2,"103606","Mary Smith"); studentClassObject = _somGetClass(student1); printf("Student count: %d \n", _countObjects(studentClassObject)); printf("student1 class object is of <%s> class\n", _somGetClassName(studentClassObject)); } The output, which had looked like: Student count: 2 student1 class object is of <StudentFactory> class now looks like: Student count: 2 student1 class object is of <M_Student> class The difference in output reflects the system assigned name of the metaclass. SUMMARY The class object is an important source of runtime information in SOM. Virtually anything that one might want to know about a class can be found out through one of the class object's methods. The class object is itself a fully functional object, like any other object in SOM. It has its own class, by default <SOMClass> which can be modified using any of the normal class modification techniques including inheritance and polymorphism. The class object is an important programmer resource. It is the source of runtime information about classes and gives the ability to make runtime decisions about how objects will be manipulated. Because the class object is a standard SOM object, instantiated from a standard SOM Class, you have considerable flexibility to redefine its characteristics as needed. REFERENCES USessionse Class Construction in C and C++: Object-Oriented Programming Fundamentals, by Roger Sessions. Prentice Hall, Englewood Cliffs, New Jersey, 1992. USessions and Coskune Object-Oriented Programming in OS/2 2.0, by Roger Sessions and Nurcan Coskun. IBM Personal Systems Developer, Winter, 1992, 107-120. USOMe OS/2 2.0 Technical Library System Object Model Guide and Reference, IBM Doc 10G6309 ACKNOWLEDGEMENTS SOM is the work of many people. Mike Conner developed the initial idea and implementation, and continues to lead the overall design of SOM. Andy Martin designed the SOM Class Interface Language, and designed and implemented the class Interface compiler. Larry Raper implemented many features of the run time library and porteed SOM to OS/2. Larry Loucks provided close technical tracking and was instrumental in focusing the effort. Other SOM developers include Nurcan Coskun, Scott Danforth, Hari Madduri, Roger Sessions, Simon Nash, and John Wang. The project is managed by Gerry Ronga. BIOGRAPHIES Roger Sessions, IBM Corporation, 11400 Burnett Road, Austin, TX 78758. He is the author of two books, Reusable Data Structures for C, and Class Construction in C and C++ - Object-Oriented Programming Fundamentals, as well as several articles. He is working on object-oriented programming environments and previously worked with high performance relational databases and object- oriented storage systems. Mr. Sessions can be contacted at roger@vnet.ibm.com. Mr. Sessions has a B.A. from Bard College and an M.E.S. in Database Systems from the University of Pennsylvania. Nurcan Coskun, IBM Corporation, 11400 Burnet Road, Austin, TX 78758. Her expertise is in integrated programming environments, code generators, incremental compilers, interpreters, language based editors, symbolic debuggers, application frameworks, and language design. She is now working on object-oriented programming environments and previously worked on the OS/2 Database Manager. Dr. Coskun can be contacted at nurcan@ausvm1.vnet.ibm.com. Dr. Coskun has a B.S. in Industrial Engineering from Middle East Technical University, an M.S. and a Ph.D. in Computer Science from the University of Missouri, Rolla.
 hobbes.nmsu.edu/download/pub/os2/dev/wps/somcla.zip
Some commonly asked questions on SOM (30/1/1995) Readme/What's new
Questions and answers about SOM 1.1: Are there plans for debugging SOM objects? response date: 5/30/92 Although SOM objects are in general multi-lingual (i.e., the instance variables and method procedures encapsulated by an object may be implemented by different languages), the newly introduced instance variables and methods for each derived class of SOM objects are always implemented by a single language, and the API for class creation can include specification of this language. Thus, the information necessary to invoke the correct debugger for tracing through individual methods can be made available. This suggests the possibility of providing a framework within which different debuggers can be dynamically called to trace method calls as execution proceeds. Currently, we use C language debuggers for debugging SOM classes implemented using C. As they become available, we may use C++ debuggers for SOM classes implemented using C++. 1.2: Does SOM support garbage collection? response date: 5/30/92 This is an area of some importance, and we may work on this in the future. Garbage collection in a multi-language environment is a hard problem, though. Even the single language case is not straightforward; take the problem of automatic garbage collection for C language programs, for example. But it is possible that enhancements to the current SOM API might be able to provide information upon which a GC capability could be based. 1.3: If SOM doesn't provide GC, then is there SOM support for freeing objects when multiple threads have access to them? response date: 5/30/92 A service or thread that creates an object (which is given to others but which may later be "deleted") has the responsibility of defining an appropriate protocol for client registration to support the object's use. SOM doesn't provide any specific support for this. Critical regions, for example, are provided by the usual operating system interfaces; not through any primitive SOM objects or classes. It should be possible to provide such facilities through SOM classes, allowing inheritance to provide uniform support of protocols. Although such classes are not provided by the basic SOM runtime, they can be provided as application frameworks. 1.4: What are the Costs/Benefits of runtime class objects? response date: 5/30/92 The cost is minimal, since there will be only one class object, no matter how many of its instances exist. The benefits are great, since the class object can respond dynamically to requests concerning object and class information that is only known at runtime. In addition, specializations of SOMClass can create metaclasses that provide additional facilities, or override SOMClass methods to provide tailored behavior for classes of objects. Since class objects are created at runtime, it is even possible to support adaptable systems in which the desired classes of objects may be discovered or may change as the system evolves. In advanced, interactive systems, the ability to create "new" kinds of objects in response to changing circumstances can be useful. 1.5: What are the Costs/Benefits of always requiring derivation from SOMObject class? response date: 5/30/92 There is no cost, since SOMObject introduces no instance variables. But there are many benefits, since this allows us to provide important functionality for all SOM objects. As an example of useful functionality, every SOM object knows its class, and can return its class object. Also, SOMObject methods allow introducing defaults for routines (like dumpSelf) that can be specialized by individual classes. There are other, deeper examples as well, related to support for dynamic method dispatching. 1.6: What SOM Class libraries are there? response date: 5/30/92 Currently the Workplace Shell and the SOM run-time classes are available for use on OS/2. Various additional class libraries are planned for the future that cover topics such as replication, persistance, event management, GUI, CORBA Interface Repository, foundation classes, etc. 2.1: What are the SOM method resolution mechanisms? response date: 5/30/92 Offset resolution is based on knowing a SOM object type that includes the desired method, and using this knowledge to access a corresponding "method token" from a global data structure. The object and the method token are passed to somResolve (the SOM procedure for offset method resolution), and the appropriate procedure pointer is returned. This pointer is then used to invoke the procedure and perform the method. Language bindings based on static information declared using OIDL are used to hide the details of this procedure. Name resolution is based on knowing the arguments for a desired method. The method name is passed to the somFindMethod method of the object's class object, and the result is the appropriate procedure pointer. Name resolution is available for any SOM object, irrespective of its class. This is because offset resolution can be used on any object to find it's class object (the somGetClass method is in the SOMObject type), and can then be used on the resulting class object to do name resolution (the somFindMethod is in the SOMClass type). The two methods above assume that it is possible to statically construct within a program a procedure call that applies the "resolved" procedure pointer to the appropriate arguments -- either explicitly, within code written by the programmer, or implicitly, within "language bindings." If the programming language does not support procedure pointers, or the appropriate arguments are not known until runtime, then dispatch resolution can be used. Dispatch resolution accepts as parameters a method name and a dynamically constructed argument list (class objects can be used to discover what the appropriate arguments for a method call are), and is available as an offset method call on all objects (since the dispatch methods are included in the SOMObject type). The different kinds of method resolution techniques thus correspond to successively greater uncertainty about the class of an object and the methods it supports. In the case of offset resolution, we have an OIDL declaration for a class that includes the desired method. In the case of name resolution, we don't have a static type for the object more specific than, often, SOMObject. But knowing only this type, we are able to use offset resolution to access the object's class, check whether the object supports a desired method (whose arguments we know), and then call the appropriate procedure. In the case of dispatch resolution, we can't use offset resolution because we don't have an appropriate type for the object, and we can't use name resolution because we don't know what the appropriate arguments are. But, as described above, the information required for dispatch resolution is always available dynamically. response date: 5/30/92 Name Resolution method : SOMClass has a method called "somFindMethod". By using this interface it is possible to get a method pointer if the object supports the specified method. This method pointer can be used to make a dynamic method call. It is a useful mechanism for optimization. Another application is that if the only information about the method call is its signature, we could use this to make the method call. Dispatch Resolution : This mechanism in SOM is created to support dynamic languages. SOMObject provides "somDispatch" interfaces which can be overridden by providing dynamic-language supported "somDispatch" routines. "somDispatch" interfaces accepts a variable argument list for the method parameters. Dynamic languages can construct a variable argument list and use this interface to send messages to SOM objects. (we use this mechanism to support subclassing of SOM classes in OREXX, Object-Oriented REXX, and vice versa) Example program: ================ student.csc file: ================= include <somobj.sc> class: Student; -- "Student" class provides a base class to generate more specialized -- students like "GraduateStudent" and "UnderGraduateStudent". -- Some of the methods like "printStudentInfo" and "getStudentType" -- must be overridden in the subclasses. parent: SOMObject; data: char idU16e; /* student id */ char nameU32e; /* student name */ methods: override somInit; void setUpStudent(char *id, char *name); -- sets up a new student. void printStudentInfo(); -- prints the student information. char *getStudentType(); -- returns the student type. char *getStudentId(); -- returns the student id. student.c file: =============== #define Student_Class_Source #include "student.ih" SOM_Scope void SOMLINK somInit(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); parent_somInit(somSelf); _idU0e = _nameU0e = ' '; } SOM_Scope void SOMLINK setUpStudent(Student *somSelf, char *id, char *name) { StudentData *somThis = StudentGetData(somSelf); strcpy(_id, id); strcpy(_name, name); } SOM_Scope void SOMLINK printStudentInfo(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); printf(" Id : %s 0, _id); printf(" Name : %s 0, _name); printf(" Type : %s 0, _getStudentType(somSelf)); } SOM_Scope char * SOMLINK getStudentType(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); static char *type = "student"; return (type); } SOM_Scope char * SOMLINK getStudentId(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); return (_id); } Client program: =============== #include "student.h" sendMessage(char *method, SOMObject *target, char *str1, char *str2) { somMethodProc *methodPtr; _somFindMethod(_somGetClass(target), somIdFromString(method), &methodPtr); (*methodPtr)(target,str1, str2); } dispatchMessage(char *method, SOMObject *target, ...) { va_list ap; va_start(ap, target); SOMObject_somDispatchV(target, somIdFromString(method), "", ap); va_end(ap); } main() { Student *student1 = StudentNew(); Student *student2 = StudentNew(); Student *student3 = StudentNew(); _setUpStudent(student1, "599600", "David Brown"); sendMessage("setUpStudent", student2, "120045", "Janet Smith"); dispatchMessage("setUpStudent", student3, "789001", "Maria Somer"); _printStudentInfo(student1); _printStudentInfo(student2); _printStudentInfo(student3); } Output from this program: ========================= Id : 599600 Name : David Brown Type : student Id : 120045 Name : Janet Smith Type : student Id : 789001 Name : Maria Somer Type : student 2.2: What might language bindings for C++ look like? Because SOM seems to omit a large subset of C++ constructs, it seems that C++ bindings may be little more than the current C bindings, save maybe the hassle of dealing with the 'this' pointer. Is this true? Will I have to give up exception handling, templates, default method arguments, operator overloading, etc..?? Will I just be basically coding in C, but compiling with C++? If these kinds of features will be available under the C++ support, will I have to use convoluted macros, or will I be able to code using the C++ semantics? If a construct is supported under one SOM language binding, will all other language bindings also have to support it? Why not make the SOM OIDL a superset of the functions provided by the popular OO languages, with some neat SOM bonus features? response date: 5/30/92 SOM is not a programming language, and does not attempted to support all of the features of all object-oriented languages. This is probably impossible and self-contradictory. SOM does provide an extremely flexible and powerful framework for advanced object-oriented systems development. The central focus and contribution of SOM is support for binary distribution of language-neutral class libraries. In contrast, language-centric class libraries are limited in utility (they are useful only from a single language), and require publication of source code (different compilers for the same object-oriented language cannot be guaranteed to use the same object layouts in memory, so a binary class library produced by one compiler will generally be useless to applications developed with a different compiler). SOM solves these problems. In general, we don't expect that SOM will be used to implement all of the objects and classes important to an application. Many objects created and used by an application will be strictly internal to that application's implementation -- with no need for being accessed by multiple languages or applications. Perhaps these internal objects will be SOM objects (in those cases where a SOM class library provides useful functionality), or perhaps they will be objects provided by some other class library (e.g., a Smalltalk or C++ class library), depending on the language used to program the application. Only objects whose implementation is to be provided or used by non-object-oriented programming languages, or objects intended to be useful across application and language boundaries with upwards binary compatability need to be SOM objects. We believe such objects can be valuable; supporting such objects is SOM's objective. --- The purpose of C++ bindings for SOM would be to make it easy for a C++ programmer to use SOM objects, and to make it easy for a C++ programmer to define new SOM object classes. There are many ways of accomplishing these two goals. We have identified at least three different approaches to C++ bindings, which may be characterized as follows: (1) Instantiable (2) Subclassable (3) Compiler-Supported Instantiable is based on in-line expansion of C++ method calls into SOM offset resolution method calls. The approach requires no C++ instance data, since the pointer to a C++ object that "wraps" a SOM object IS the pointer to the wrapped SOM object. Subclassable is based on C++ instance data that holds a pointer to a wrapped SOM object, and uses a C++ virtual function table. Either approach could be supported by a special C++ compiler front-end, which would provide the corresponding functionality, while optimizing performance. What are the functionalities associated with (1) and (2) ? With (1), Instantiable: All SOM objects (including class objects) are available to a C++ programmer as C++ objects of a corresponding C++ class. Such SOM objects can be created using the C++ "new" operation on the C++ class name. The SOM class hierarchy is faithfully mirrored in the C++ class hierarchy. As a result, the C++ compiler provides static typechecking for SOM object use. A C++ programmer using the SOM bindings to access SOM objects thus has access to all of C++ in his code. (The important qualification here is the use of the word "object" instead of the word "class" -- see the next paragraph). If it is desired to implement an OIDL-specified class using C++, an OIDL specification for the desired SOM class is provided as input to the SOM compiler, and C++ implementation bindings for the class are generated and used by the C++ programmer. The C++ programmer uses (unrestricted) C++ code to implement procedures supporting the newly-introduced methods of the class. Thus, individual C++ procedures (not C++ methods) are defined to support the methods introduced and overridden by the OIDL- specified class. Of course, using "this" within such procedures is meaningless. The C++ methods in which "this" is used contain the (inline) SOM offset resolution method calls that are used to invoke the supporting procedures. The primary difference from the C implementation bindings is that the new class can introduce C++ instance variables (including C++ objects), and the method procedures used to implement new and overridden methods can make use of local C++ variables (again, including C++ objects). Thus, subclassing is done in OIDL -- not C++ -- and all parent classes must themselves be SOM classes. The C++ classes that mirror SOM classes, and whose instances are actually SOM objects, cannot be subclassed in C++. Only the mirrored SOM classes themselves can be subclassed (using OIDL and some choice of implementation bindings). With (2), Subclassable: As with the Instantiable approach, SOM objects (including classes) are available to a C++ programmer as an instance of a C++ class, and the SOM class hierarchy is faithfully mirrored in the C++ class hierarchy. As a result, the C++ compiler provides static typechecking for SOM object use. But subclassing can now be done in C++. A C++ subclass can be derived (in C++) from the C++ representative of a SOM class, and can introduce new instance variables and methods, and override inherited methods. This allows a new C++ class to be derived from both C++ and SOM classes. Unfortunately, using language bindings to allow C++ to override inherited SOM methods and pass C++ objects as arguments to SOM methods introduces performance penalties. Some of these can be avoided in a compiler-supported approach. Using a dual approach, C++ classes can be made available as SOM class, through an interface that provides the SOM benefits. Again, there are performance tradeoffs. 2.3: How about inter-process method calls? response date: 5/30/92 This capability is planned. Currently, SOM can be used with shared memory for this purpose (this is not a supported capability, but some users are doing it). But SOM is being enhanced to support the CORBA standards for object method invocation in a distributed open system environment. As an initial step in this directions, we will be supporting calls across address spaces on a single machine. Also, classes being developed as class libraries may provide automated support for replicated objects across address spaces (i.e., one "logical" object; many "physical" copies). 2.4: Will SOM and the WPS be supported on multiple platforms (other than AIX)? response date: 6/1/92 We're working on getting SOM available on AIX. As for the WPS, we don't know if there are plans or a desire to put it on AIX. As for other platforms for SOM, there don't appear to be any technical barriers. 2.5: What does it take for another language to be supported under SOM? Once a language is supported, does this mean that any standard compiler for that language will do? response date: 5/30/92 To allow a given language to use and define class of SOM objects, we decide how to map the types and objects of SOM into this other language. There may be many ways to do this; we decide on one, and then write emitters that automate the process. Then all that is needed is a standard compiler for the language, plus use of the emitters to produce SOM class bindings. This has currently been done for C and C++. We are working on other languages as well. The above approach assumes that it is possible to make use of the SOM API from within the language for which bindings are desired. The SOM API was designed with the desire to require as little as possible for its use. The SOM API basically requires the ability to make external procedure calls using system-defined linkage, and the ablity to construct simple data structures in memory. Where these capabilities are available at the language level, SOM bindings can be source level; where they are not, SOM bindings will require compiler support, in addition to any source-level bindings that might be used. 2.6: How does SOM implement language independence? response date: 5/30/92 Discussion of language independence in SOM ultimately relates to the ability of different languages to use SOM objects and define new SOM classes (which, really, is simply a use of SOM objects). It is not SOM's most direct purpose to allow C++ programmers to invoke virtual functions on Smalltalk objects, or allow C++ to subclass Smalltalk classes. SOM does allow both C++ and Smalltalk (as well as other languages) to use SOM objects and to implement new classes of SOM objects by inheriting and enhancing the implementation of other classes of SOM objects. As a result of this capability, SOM does reduce an order n-squared interface problem to an order n interface problem. In addition, SOM does provide facilities that are useful in this reguard. Multi-language capability is a primary objective for SOM. Achieving this objective has influenced SOM's design in many ways, so there is no single answer to this question. As we produce new language bindings for SOM, we are likely to iterate the SOM design (while maintaining binary capability with previous versions) to provide better support for this. The SOM API for invoking methods on SOM objects is ultimately based on calls to external procedures defined by the SOM runtime, a small set of simple types (including pointers to data and pointers to procedures) and few simple data structures. Any languages with these capabilities can use SOM directly. Where these facilities are not available directly at the language level, it is possible they might be provided by "helper functions," provided by a compiler-specific procedure library, or they might be directly supported by compiler modifications. When a given language is used to implement a new SOM class, the instance variables that are introduced, and the procedures used to support introduced and overridden methods need not be useful (or comprehensible) to the languages used to implement subsequently derived classes. This is one reason why SOM does not allow inherited access to instance variables. As a result, multi-language objects are possible, in which instance variables and method procedures are contributed by different programming languages. When a method is invoked on a SOM object, the appropriate procedure is called, and this procedure then can directly access only those instance variables that were introduced by the class the procedure supports. For obvious reasons, we have initially focused on the cases in which the SOM API is useful without compiler-specific support. But as interest in SOM grows, it is likely that we will also be investigating other possibilities. Due to the simplicity of the SOM API, compiler modifications necessary for its support should be straightforward. For example, a compiler vendor for a non- object-oriented language without the ability to directly use the SOM API might consider the ability to use SOM objects a strategic advantage worth the small effort involved in providing this capability through compiler modifications. 3.1: Is there a problem when two unrelated classes introduce methods of the same name, and a client code wants to deal with objects of both classes? What if the methods take a different number of arguments? response date: 6/10/92 This would not a problem at all with C++ bindings (since C++ classes provide method scoping). The C bindings for SOM, however, are based on macros, so method "collision" in this case, as a result of different macros being #included into C source that deals with different classes of objects, is something that can happen. When this does happen, however, it is not a serious problem (it is an annoyance, and the following describes how to deal with it). In the C bindings, corresponding to any given method on a SOM object are two different invocation macros: a "short" form in which the macro name contains only the method name (e.g., _foo for the method foo); and a "long" form, in which the macro name includes both the class that introduced the method and, in addition, the method name. Certainly, if class A and class B both define a foo method, and some client code includes both A.h and B.h, then the short forms of the macros will "collide." This is will result in either warning messages or error messages -- depending on the particular C compiler being used. For example, assume that the foo method available on A instances was introduced by the class, Z, an ancestor of A, and that the foo method available on B instances was introduced by the class, B. Then the following code should be used. #include "A.h" #undef _foo #include "B.h" #undef _foo void test(A *a, B *b) { Z_foo(a); /* instead of _foo(a) */ B_foo(b,12); /* instead of _foo(b,12) */ } The only important thing is this: if you see a warning that a method invocation macro has been redefined, then it is absolutely essential that the long form of the method invocation macros be used. Note that in the above example, the methods take different numbers of arguments, as in your question. The #undef's prevent the warning (or error) messages, and also prevent accidental use of the short form. Again Note: The C++ bindings would not have this problem, because they would not be based on macros, but, instead, inline C++ method expansions. 3.2: Why do the usage bindings for a class automatically include usage bindings for its parent (which, in turn include the usage bindings for its parent, and so on until SOMObject is reached)? The result is that if a client includes the usage bindings for a given class, then the usage bindings for all of that class's ancestors are included as well. response date: 6/10/92 First off, this should not be a surprise to anyone familiar with C++, since any client of a C++ class must include the class's structure definition, and defining a class's structure can only be done after defining the structure of the parent classes. So a very similar sort of chaining effect occurs in within any code that uses a C++ class. Why is it necessary in SOM, though? As in C++, it is required for implementing inheritance of interface. The method invocation macros that support the methods introduced by any given class initially appear in the usage bindings for the introducing class, and these must be "inherited" by the usage bindings for classes derived from this class. Also, to actually accomplish a static method call ultimately requires to evaluate an expression that accesses the ClassData structure of the class that introduced the method. And this data structure is defined in the usage bindings for the introducing class. If, for example, the usage bindings for SOMObject were not included by some derived class's usage bindings, then none of the methods introduced by SOMObject would be available statically on instances of the derived class. 3.3: Why isn't access to data inherited? response date: 6/10/92 First it is necessary to understand that the SOM API does allow direct (uninterpreted, offset-based) access to the instance variables of SOM objects. As a matter of policy, however, the usage bindings for SOM classes do not automatically provide an interface to this capability. Some reasons for this explained below. However, the SOM API is always available directly to users, so direct access to instance variables is possible if an application is willing to suffer the consequences: changes in implementation of the class whose introduced instance variables are accessed may require recompilation of the application's source code. Within tightly-coupled "friend" classes, this may be reasonable. SOM simply doesn't provide this facility as a default. Instead, SOM provides a machanism whereby a SOM class developer decides which instance variables introduced by that class should be visible to clients, and for these instance variables (and only these) is an interface provided by the usage bindings for that class. The following are two reasons for our approach. (1) SOM is intended to support arbitrary languages, allowing a subclass to be implemented independently of the language(s) used to implement its ancestor classes. Typically, a class C implemented using language X will introduce instance variables to support its methods. Now, lets say that language Y is now used to implement a subclass of C named S. S will also introduce instance variables in support of its methods. Certainly, the code that implements these methods should have direct access to the instance variables that were introduced for its support. But there is no reason whatsoever to expect that the instance variables that make sense to language X (used in support of C's method procedures) will also make sense to language Y (used in support of S's method procedures). Given SOM's desire to support multi-language objects, there seems very little reason for believing that inherited access to instance variables introduced by ancestor classes makes sense in general. Thus, the procedures that implement methods introduced by a class have direct access only to those instance variables introduced by the class. (2) There is another reason related to binary compatibility. SOM's objective is that changing the implementation for a class of objects should not require re-compiling any code that depends on this class. Code that depends on a class includes both client code, and code that implements subclasses. Now, if the code that implements a subclass were allowed direct access to inherited instance variables, this code would certainly require recompilation (and more likely, redesign) when implementation of an ancestor class changes. SOM does provide access mechanisms for instance variables, but the decision to "publish" an instance variable for access by others is a decision of the class implementor -- not the class user. So the class implementor knows what portions of the implementation others could depend on, and what portions can be changed without concern for users. As mentioned above, it is possible to defeat approach, but it must be done with knowledge of the SOM API -- the language bindings (which hide the API) don't provide direct support for it. 3.4: Is the interface to published methods a macro or a function. response date: 6/10/92 Just as with access to instance data, access to the procedure that supports a given method is based on a function call. The two situations are very similar. To access data (using the SOM API directly), one calls somDataResolve passing an object and a data token. To access the procedure that supports a method, one calls somResolve passing an object and a method token. Both data and method tokens can be thought of as "logical" offsets. They provide a very fast way of accessing the desired information, and are statically available via usage bindings. As with data access, usage bindings try to hide the details. In the C bindings, this is done with a macro; in the C++ bindings, this may be done by defining C++ methods as expanded inline. The result is the same, since the same function call is compiled inline in both cases. In drastic contrast, name lookup first requires getting the class of the object, and then invoking methods on the class to get a method token. This is rather more expensive than simply retrieving a method token from a known, globally available location (which is what the usage bindings do for static method invocations). Once the method token is available, somResolve is used to return a pointer to the procedure that supports the desired method on the object. 3.5: There is a problem with the _<class-name>New macro. Unlike the <class-name>New macro (note no underscore prefix). Using the first may create errors, since it assumes that the class object exists. response date: 6/10/92 The underscore form of the macro is certainly not intended for use by class clients. It is defined within the usage bindings solely to support the non-underscore form, which is the (only) form documented in the SOM user's guide. This could cause a problem, though, since the short form for method invocation starts with an underscore, and a SOM user thus might forget and use the underscore when requesting instance creation. This has been been fixed. (I.e., the underscore form of the macro is no longer defined defined.) In general, the macro-based C usage bindings are open to a number of similar criticisms. The C++ bindings would not suffer from this problem, since they would not be macro-based. 4.1: Is there a version of SOM that is OMG (CORBA) compliant? response date: 6/12/92 We are currently working upon a CORBA compliant version of SOM. This will include an IDL compiler (with suitable enhancements to accept SOM Class Implementation details) and all SOM runtime classes in IDL. 5.1: For example, if I had a "C++ binding" for the workplace shell classes, what might a C++ programmer write in order to subclass "WPAbstract"? response date: 6/30/92 Instantiable ============ First of all, with the "Instantiable" approach, it is not necessary to have a C++ binding for WPAbstract in order to implement a subclass of WPAbstract using C++. All that is needed is an OIDL class description (e.g., the .sc file) for WPAbstract. Assuming that the .sc file for WPAbstract is available, a C++ programmer would (1) use OIDL to declare a new SOM class whose parent is WPAbstract, (2) generate Instantiable C++ implementation bindings for the resulting subclass, and (3) fill out the resulting default method procedure templates for overridden and newly-introduced methods with C++ code. As can be seen, this is essentially the same approach used for the C implementation bindings. How is this different from using C implementation bindings to implement a new subclass of WPAbstract? The two primary differences are that the instance variables introduced by the new subclass can include C++ objects, and the method procedures used by the C++ programmer to implement the overridden and newly introduced methods for the new class can make use of local variables that are C++ objects. Of course, C++ usage bindings for a SOM class should be a great improvement over the C usage bindings, since the C++ usage bindings can be based on inline method expansion instead of macros, resulting in the elimination of any macro "collision" problems of the C bindings. Also a C++ compiler could then type check SOM object usage. Subclassable ============ With the Subclassable approach, a C++ programmer would use a C++ class representing the SOM class WPAbstract (provided by the Subclassable C++ bindings for WPAbstract) as a base class for declaring and defining (in C++ -- not OIDL) a new derived C++ class whose parent is the C++ class provided by the C++ usage bindings for WPAbstract. This new derived C++ class is not a SOM class. However, if it is desired to publish this new subclass as a SOM class (thereby making it available and useful to languages other than C++), then it is possible to do this -- using essentially the same technique as was used to create the Subclassable C++ bindings for WPAbstract. The Subclassable bindings would be more complex and present additional execution-time tradeoffs. We have created prototype emitters to demonstrate that the process of generating these bindings can be automated, and we are currently evaluating tradeoffs.
 hobbes.nmsu.edu/download/pub/os2/dev/wps/som_qa.zip
Object-Oriented Programming in OS/2 2.0 Using SOM (22/9/1992, Roger Sessions, Nurcan Coskun) Readme/What's new
Object-Oriented Programming in OS/2 2.0 Using SOM by Roger Sessions Nurcan Coskun -------------------------------------------------------- THIS ARTICLE WAS ORIGINALLY PUBLISHED IN THE PERSONAL SYSTEMS DEVELOPER WINTER 1992 AND IS COPYRIGHT BY IBM. THIS ARTICLE MAY NOT BE REPRINTED IN WHOLE OR IN PART WITHOUT PERMISSION. ABSTRACT Object-Oriented Programming is quickly establishing itself as an important methodology in developing high quality, reusable code. In the 2.0 release of OS/2, IBM is introducing a new system for developing class libraries and Object-Oriented programs. This system is called SOM for System Object Model. This paper gives a general introduction to the Object-Oriented Paradigm, discusses developing Object-Oriented class libraries using SOM, and compares SOM libraries to those developed using standard Object- Oriented languages. INTRODUCTION TO OBJECT-ORIENTED PROGRAMMING The latest revolution to hit the software community is Object- Oriented Programming. Object-Oriented Programming Languages (OOPL) are being used throughout the industry, Object-Oriented Databases (OODB) are starting elicit widespread interest, and even Object-Oriented Design and Analysis (OODA) tools are changing the way people design and model systems. Object-Oriented Programming is best understood in contrast to its close cousin, Structured Programming. Both attempt to deal with the same basic issue, managing the complexity of ever more complex software systems. Structured Programming models a system as a layered set of functional modules. These modules are built up in a pyramid like fashion, each layer representing a higher level view of the system. Structured Programming models the system's behavior, but gives little guidance to modeling the system's information. Object-Oriented Programming models a system as a set of cooperating objects. Like Structured Programming, it tries to manage the behavioral complexity of a system. Object-Oriented Programming, however, goes beyond Structured Programming in also trying to manage the informational complexity of a system. Because Object-Oriented Programming models both the behavioral and informational complexity of a system, the system tends to be much better organized than if it was simply well "structured". Because Object-Oriented systems are better organized, they are easier to understand, debug, maintain, and evolve. Well organized systems also lend themselves to code reuse. Object-Oriented Programming sees the dual issues of managing informational and behavioral complexity as being closely related. Its basic unit of organization is the object. Objects have some associated data, which we call the object's state, and a set of behaviors, which we call the object's methods. A class is a general description of an object, which defines the data which represents the object's state, and the methods the object supports. OBJECT-ORIENTED PROGRAMMING IN C Before we examine SOM, let's consider Object-Oriented Programming in C; this will lead us naturally into the SOM philosophy. The techniques in this section as well as many related advanced C coding techniques are discussed in the book Reusable Data Structures for C USessions, 89e. Consider a data structure definition containing information related to a generic stack. We may have a series of functions all designed to operate on our stack structure. Given a basic stack definition, we may have multiple instances of this structure declared within our program. Our generic stack definition, in C, might look like struct stackType { void *stackArrayUSTACK_SIZEe; int stackTop; }; typedef struct stackType Stack; We could define some generic stack functions, say Stack *create(); /* malloc and initialize a new stack. */ void *pop( /* Pop element off stack. */ Stack *thisStack); void push( /* Push new element onto stack. */ Stack *thisStack, void *nextElement); Most C programmers can imagine how such functions would be written. The push() function, for example, would look like void push(Stack *thisStack, void *nextElement) { thisStack->stackArrayUthisStack->stackTope = nextElement; thisStack->stackTop++; } A client program might use this stack to, say, create a stack of words needing interpretation: main() { Stack *wordStack; char *subject = "Emily"; char *verb = "eats"; char *object = "ice cream"; char *nextWord; wordStack = create(); push(wordStack, object); push(wordStack, verb); push(wordStack, subject); /* ... */ while (nextWord = pop(wordStack)) { printf("%s\n", nextWord); /* ... */ } } Using this example, let's look at the language of Object-Oriented Programming. A class is a definition of an object. The definition includes the data elements of the object and the methods it supports. A stack is an example of a class. We say that a stack contains two data elements (stackArray and stackTop), and supports three methods, create(), push(), and pop(). A method is like a function, but is designed to operate on an object of a particular class. An object is a specific instance, or instantiation, of a class. We say wordStack is an object of class Stack, or wordStack is an instance of a stack. Every method needs to know the specific object on which it is to operate. We call this object the target object, or sometimes the receiving object. Notice that each method (except create()) takes as its first parameter a pointer to the target object. This is because a program may have many objects of a given class, and each are potential targets for the class methods. There are three important advantages of this type of organization. First, we are developing some generic concepts, which can be reused in other situations in which similar concepts are appropriate. Second, we are developing self-contained code, which can be fully tested before it is folded into our program. Third, we are developing encapsulated code, the internal details of which are hidden and of no interest to the client. Our client main() program need know nothing about the Stack class other than its name, the methods it supports, and their interfaces. INTRODUCTION TO SOM OS/2 2.0 includes a language-neutral Object-Oriented programming mechanism called SOM (for System Object Model). Although it is possible to write Object-Oriented programs in traditional languages, such as we did with the stack example, SOM is specifically designed to support the new paradigm and to be usable with both procedural (or non Object-Oriented) languages and Object-Oriented languages. A major claim of Object-Oriented programming is code reusability. This is most often achieved through the use of class libraries. Today's library technology is limited in that these class libraries are always language specific. A C++ library cannot be used by a Smalltalk programmer, and visa versa. Clearly there is a need to create a language-neutral object model, one which can be used to create class libraries usable from any programming language, procedural or Object-Oriented. SOM is designed to address this need. SOM introduces three important features lacking in most procedural languages. These are encapsulation, inheritance, and polymorphism (referred to here as "override resolution"). Encapsulation means the ability to hide implementation details from clients. This protects clients from changes in our implementation, and protects our implementation from tinkering by clients. Our stack example was not protected. Although clients did not need to know the internal data structures of the stack, we had no way to prevent clients from looking at such implementation details. We could discourage, but not prevent, clients from writing code which used, and possibly corrupted, internal stack data elements. Inheritance, or class derivation, is a specific technique for developing new classes from existing classes. It allows one to create new classes which are more specialized versions of existing classes. For example, we could create a DebuggableStack, which is like a Stack class, but supports further debugging methods, such as peek() and dump(). Inheritance also allows code consolidation. If we have a class defining GraduateStudent and UnderGraduateStudent, we can consolidate common code into a third class, Student. We then define GraduateStudent and UnderGraduate as more specialized classes, both derived from the common parent Student. Inheritance introduces some additional semantics beyond those we have already examined. A specialized class is said to be derived from a more generalized class. The general class is called the parent class, or sometimes, the base class. The specialized class is called the child class, or sometimes, the derived class. A child class is said to inherit the characteristics of its parent class, meaning that any methods defined for a parent are automatically defined for a child. Thus because GraduateStudent and UnderGraduateStudent are both derived from Student, they both automatically acquire any methods declared in their common parent. Override resolution means invoked methods are resolved based not only on the name of the method, but also on a class's place within a class hierarchy. This allows us to redefine methods as we derive classes. We might define a printStudentInfo() method for Student and then override, or redefine, the method in both UnderGraduateStudent, and GraduateStudent. Override resolution means that the method is resolved based on the type of the target object. If the target object type is a Student, the Student version of printStudentInfo() is invoked. If the target object type is a GraduateStudent, the GraduateStudent version of printStudentInfo() is invoked. We will now look at SOM in more detail by examining how classes are defined in SOM, how SOM methods are written in the C programming language, and how clients use SOM classes. SOM will eventually allow developers to write methods in a variety of languages including the popular Object-Oriented programming languages. In OS/2 2.0, SOM support is limited to C, thus the language used in the examples. DEFINING CLASSES IN SOM The process of creating class libraries in SOM is a three step process. The class designer defines the class interface, implements the class methods, and finally loads the resulting object code into a class library. Clients either use these classes directly, make modifications to suit their specific purposes, or add entirely new classes of their own. In SOM we define a class by creating a class definition file. We will give a basic example here, and defer more detailed discussion of the many keywords and options to the SOM manuals USOMe. The class definition file is named with an extension of "csc". In its most basic form, the class definition file is divided into the following sections: 1. Include section This section declares files which need to be included, much like the C #include directive. 2. Class name and options This section defines the name of the class and declares various options. 3. Parent information This defines the parent, or base, class for this class. All classes must have a parent. If your class is not derived from any of your own classes, than it's parent will be the SOM defined class SOMObject, the class information of which is in the file somobj.sc. 4. Data Section This section declares any data elements contained by objects of this class. By default, data can be accessed only by methods of the class. 5. Methods Section This section declares methods to which objects of this class can respond. By default, all methods declared in this section are available to any class client. Comments can be used for documentation purposes, and the following styles are all acceptable: /* This is a comment. */ // This is a comment. -- This is a comment. The class definition file, student.csc, describes a non-derived Student class, and is shown in figure 1. ((start figure 1, caption: Class Definition File: student.csc)) include <somobj.sc> class: Student; -- "Student" class provides a base class to generate more -- specialized students like "GraduateStudent" and -- "UnderGraduateStudent". parent: SOMObject; data: char idU16e; /* student id */ char nameU32e; /* student name */ methods: void setUpStudent(char *id, char *name); -- sets up a new student. void printStudentInfo(); -- prints the student information. char *getStudentType(); -- returns the student type. char *getStudentId(); -- returns the student id. ((end table)) WRITING METHODS Class methods are implemented in the class method implementation file. Each method defined in the method section of the class definition file needs to be implemented. They can be implemented in any language that offers SOM support, which for now is only C. The student class method implementation file, student.c, is shown in figure 2. ((start figure 2, caption: Class Method Implementation File: student.c)) #define Student_Class_Source #include "student.ih" static void setUpStudent( Student *somSelf, char *id, char *name) { StudentData *somThis = StudentGetData(somSelf); strcpy(_id, id); strcpy(_name, name); } static void printStudentInfo(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); printf(" Id : %s \n", _id); printf(" Name : %s \n", _name); printf(" Type : %s \n", _getStudentType(somSelf)); } static char *getStudentType(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); static char *type = "student"; return (type); } static char *getStudentId(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); return (_id); } ((end figure 2)) Notice that the method code looks much like standard C, with a few differences. First, each method takes, as its first parameter, a pointer (somSelf) to the target object. This is very similar to our C stack implementation. This parameter is implicit in the class definition file, but is made explicit in the method implementation. Second, each method starts with a line setting an internal variable named somThis, which is used by macros within the SOM header file. Third, names of data elements of the target object are preceded by an underscore character. The underscored name turns into a C language macro defined in the class header file, part of the package SOM offers to shield method developers from the details of memory layout. Fourth, methods are invoked using an underscored syntax. This underscored name turns into a macro invocation which shields programmers from having to understand the details of method resolution. The first parameter of every method is always a pointer to the target object. This can be seen in the method printStudentInfo() which invokes the method getStudentType() on its own target object. The process of creating a class method implementation file can be greatly speeded up by the SOM compiler, which creates a valid C method implementation file lacking only the body of the methods. The body is then filled in by the class implementor. For the student example, the SOM compiler would create a file similar to the one shown in figure 3. ((start figure 3, caption: SOM compiler generated student.c)) #define Student_Class_Source #include "student.ih" static void setUpStudent( Student *somSelf, char *id, char *name) { StudentData *somThis = StudentGetData(somSelf); } static void printStudentInfo(Student *somSelf) { StudentData *somThis = StudentGetData(somSelf); } /* ...and so on for the other methods. */ ((end figure 3)) MECHANICS OF USING SOM There is a set of files involved with each class. Here we will look at the most important of these files and discuss their purpose and how they are created. They have different extensions, but all have the same filename as the class definition file, Student in our example. The SOM compiler generates files based on the value of an environment variable, as described in the SOM users guide USOMe. These files are described in table 1. ((start table 1, caption: Student Class Files)) student.csc - This is the class definition file, as described earlier. student.sc - This is a subset of the class definition file. It includes all information from the .csc file which is public, including comments on public elements. For the student example, student.sc would include everything from student.csc except the data section. This file is created by the SOM compiler, and although human readable, should not be edited, as it will be regenerated whenever changes are made to the .csc file. student.h - This is a valid C header file which contains macros necessary to invoke public methods and access public data elements of the class. This file will be included in any client of the class. This file is created by the SOM compiler, and is normally only read by programmers who need to know how method resolution is implemented. This file should not be edited. student.ih - Similar to student.h, but contains additional information needed for implementing methods. This is the implementor's version of the .h file, and must be included in the class methods implementation file. This file is created by the SOM compiler and should not be edited. student.c - Contains the method implementations. This is initially created by the SOM compiler and then updated by the class implementor. ((end table1) BUILDING SOM CLASSES FROM OTHER CLASSES There are two ways to use classes as building blocks for other classes. These are derivation (or inheritance) and construction. Let's consider derivation first. In this example, GraduateStudent is derived from Student, its base, or parent class. A derived class automatically picks up all characteristics of the base class. A derived class can add new functionality through the definition and implementation of new methods. A derived class can also redefine methods of its base class, a process called overriding. GraduateStudent adds setUpGranduateStudent() to those methods it inherits from Student. It overrides two other inherited methods, printStudentInfo() and getStudentType(). It inherits without change setUpStudent() and getStudentId() from the Student base class. The class definition file for GraduateStudent, graduate.csc, is shown in figure 4. ((start figure 4, caption: Class Definition File: graduate.csc)) include <student.sc> class: GraduateStudent; parent: Student; data: char thesisU128e; /* thesis title */ char degreeU16e; /* graduate degree type */ methods: override printStudentInfo; override getStudentType; void setUpGraduateStudent( char *id, char *name, char *thesis, char *degree); ((end figure 4)) The method implementation file, graduate.c, is shown in figure 5. ((start figure 5, caption: Class Method Implementation File: graduate.c)) #define GraduateStudent_Class_Source #include "graduate.ih" static void printStudentInfo(GraduateStudent *somSelf) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); parent_printStudentInfo(somSelf); printf(" Thesis : %s \n", _thesis); printf(" Degree : %s \n", _degree); } static char *getStudentType(GraduateStudent *somSelf) { static char *type = "Graduate"; return (type); } static void setUpGraduateStudent( GraduateStudent *somSelf, char *id, char *name, char *thesis, char *degree) { GraduateStudentData *somThis = GraduateStudentGetData(somSelf); _setUpStudent(somSelf,id,name); strcpy(_thesis, thesis); strcpy(_degree, degree); } ((end figure 5)) Often an overridden method will need to invoke the original method of its parent. For example, the printStudentInfo() for GraduateStudent first invokes the Student version of printStudentInfo() before printing out the GraduateStudent specific information. The syntax for this is "parent_MethodName", as can be seen in the printStudentInfo() method. A given base class can be used for more than one derivation. The class, UnderGraduateStudent, is also derived from Student. The class definition file, undgrad.csc, is shown in figure 6. ((start figure 6, caption: Class Definition File: undgrad.csc)) include <student.sc> class: UnderGraduateStudent; parent: Student; data: char dateU16e; /* graduation date */ methods: override printStudentInfo; override getStudentType; void setUpUnderGraduateStudent( char *id, char *name, char *date); ((end figure 6)) The method implementation file, undgrad.c, is shown in figure 7. ((start figure 7, caption: Class Method Implementation File: undgrad.c)) #define UnderGraduateStudent_Class_Source #include "undgrad.ih" static void printStudentInfo( UnderGraduateStudent *somSelf) { UnderGraduateStudentData *somThis = UnderGraduateStudentGetData(somSelf); parent_printStudentInfo(somSelf); printf(" Grad Date : %s \n", _date); } static char *getStudentType(UnderGraduateStudent *somSelf) { static char *type = "UnderGraduate"; return (type); } static void setUpUnderGraduateStudent( UnderGraduateStudent *somSelf,char *id, char *name, char *date) { UnderGraduateStudentData *somThis = UnderGraduateStudentGetData(somSelf); _setUpStudent(somSelf,id,name); strcpy(_date, date); } ((end figure 7)) The second technique for building classes is construction. This means that a class uses another class, but not through inheritance. A good example of construction is the class Course which includes an array of pointers to Students. Each pointer contains the address of a particular student taking the course. We say that Course is constructed from Student. The class definition file for Course, course.csc, is shown in figure 8. ((start figure 8, caption: Class Definition File: course.csc)) include <somobj.sc> class: Course; -- "Course" class describes the interfaces required to setup the -- course information. The students are "Student" class type and -- can be added to or dropped from the courses through the -- "addStudent" and "dropStudent" methods. parent: SOMObject; data: char codeU8e; /* course code number */ char titleU32e; /* course title */ char instructorU32e; /* instructor teaching */ int credit; /* number of credits */ int capacity; /* maximum number of seats */ Student *studentListU20e;/* enrolled student list */ int enrollment; /* number of enrolled students */ methods: override somInit; void setUpCourse(char *code, char *title, char *instructor, int credit, int capacity); -- sets up a new course. int addStudent(Student *student); -- enrolls a student to the course. void dropStudent(char *studentId); -- drops the student from the course. void printCourseInfo(); -- prints course information. ((end figure 8)) Often classes will want to take special steps to initialize their instance data. An instance of Course must at least initialize the enrollment data element, to ensure the array index starts in a valid state. The method somInit() is always called when a new object is created. This method is inherited from SOMObject, and can be overridden when object initialization is desired. This example brings up an interesting characteristic of inheritance, the "is-a" relationship between derived and base classes. Any derived class can be considered as a base class. We say that a derived class "is-a" base class. In our example, any GraduateStudent "is-a" Student, and can be used anyplace we are expecting a Student. The converse is not true. A base class is not a derived class. A Student can not be treated unconditionally as a GraduateStudent. Thus elements of the array studentList can point to either Students, a GraduateStudents, or a UnderGraduateStudents. The method implementation file for Course, course.c, is shown in figure 9. ((start figure 9, caption: Class Method Implementation File: course.c)) #define Course_Class_Source #include <student.h> #include "course.ih" static void somInit(Course *somSelf) { CourseData *somThis = CourseGetData(somSelf); parent_somInit(somSelf); _codeU0e = _titleU0e = _instructorU0e = '\0'; _credit = _capacity = _enrollment = 0; } static void setUpCourse(Course *somSelf, char *code, char *title, char *instructor, int credit, int capacity) { CourseData *somThis = CourseGetData(somSelf); strcpy(_code, code); strcpy(_title, title); strcpy(_instructor, instructor); _credit = credit; _capacity = capacity; } static int addStudent(Course *somSelf, Student *student) { CourseData *somThis = CourseGetData(somSelf); if(_enrollment >= _capacity) return(-1); _studentListU_enrollment++e = student; return(0); } static void dropStudent(Course *somSelf, char *studentId) { int i; CourseData *somThis = CourseGetData(somSelf); for(i=0; i<_enrollment; i++) if(!strcmp(studentId, _getStudentId(_studentListUie))) { _enrollment--; for(i; i<_enrollment; i++) _studentListUie = _studentListUi+1e; return; } } static void printCourseInfo(Course *somSelf) { int i; CourseData *somThis = CourseGetData(somSelf); printf(" %s %s \n", _code, _title); printf(" Instructor Name : %s \n", _instructor); printf(" Credit = %d, Capacity = %d, Enrollment = %d \n\n", _credit, _capacity, _enrollment); printf(" STUDENT LIST: \n\n"); for(i=0; i<_enrollment; i++) { _printStudentInfo(_studentListUie); printf("\n"); } } ((end figure 9)) Notice in particular the method printCourseInfo(). This method goes through the array studentList invoking the method printStudentInfo() on each student. This method is defined for Student, and then overridden by both GraduateStudent and UnderGraduateStudent. Since the array element can point to any of these three classes, we can't tell at compile time what the actual type of the target object is, only that the target object is either a Student or some type derived from Student. Since each of these classes defines a different printStudentInfo() method, we don't know which of these methods will be invoked with each pass of the loop. This is all under the control of override resolution. THE SOM CLIENT Now let's see how a client might make use of these four classes in a program. As we look at the program example shown in figure 10, we can discuss how objects are instantiated, or created, in SOM, and how methods are invoked. ((start figure 10, caption: SOM client code)) #include <student.h> #include <course.h> #include <graduate.h> #include <undgrad.h> main() { Course *course = CourseNew(); GraduateStudent *jane = GraduateStudentNew(); UnderGraduateStudent *mark = UnderGraduateStudentNew(); _setUpCourse(course, "303", "Compilers ", "Dr. David Johnson", 3, 15); _setUpGraduateStudent(jane,"423538","Jane Brown", "Code Optimization","Ph.D."); _setUpUnderGraduateStudent(mark,"399542", "Mark Smith", "12/17/92"); _addStudent(course, jane); _addStudent(course, mark); _printCourseInfo(course); } ((end figure 10)) A class is instantiated with the method classNameNew(), which is automatically defined by SOM for each recognized class. Methods are invoked by clients just as they are inside SOM methods, and very similarly to our earlier C examples. The first parameter is the target object. The remaining parameters are whatever information is needed by the method. The only odd feature is the underscore preceding the method name, which turns what looks like a regular function call into a macro defined in the .h file. When run, the client program gives the output shown in figure 11. ((start figure 11, caption: Client Program Output)) 303 Compilers Instructor Name : Dr. David Johnson Credit = 3, Capacity = 15, Enrollment = 2 STUDENT LIST: Id : 423538 Name : Jane Brown Type : Graduate Thesis : Code Optimization Degree : Ph.D. Id : 399542 Name : Mark Smith Type : UnderGraduate Grad Date : 12/17/92 ((end figure 11)) In the client program output we can see the override resolution at work in the different styles of displaying UnderGraduates and GraduateStudents. A Course thinks of itself as containing an array of Students, and knows that any Student responds to a printStudentInfo() method. But the printStudentInfo() method that a UnderGraduate responds to is different than the printStudentInfo() method that a GraduateStudent responds to, and the two methods give different outputs. COMPARISON TO C++ In this section we will compare some SOM features to those of the most widespread Object-Oriented programming language, C++, developed by Bjarne Stroustrup. Some good introductory books about Object-Oriented programming in C++ are Class Construction in C and C++ USessions, 91e, The C++ Programming Language UStroustrupe, and C++ Primer ULippmane. SOM has many similarities to C++. Both support class definitions, inheritance, and overridden methods (called virtual methods in C++). Both support the notion of encapsulation. But whereas C++ is designed to support standalone programming efforts, SOM is primarily focused on the support of commercial quality class libraries. Most of the differences between SOM and C++ hinge on this issue. C++ class libraries are version dependent, while SOM class libraries are version independent. When a new C++ class library is released, client code has to be fully recompiled, even if the changes are unrelated to public interfaces. This problem is discussed in detail in the book Class Construction in C and C++ USessions, 91e. SOM, unlike C++, directly supports the development of upwardly compatible class libraries. C++ supports programming in only one language, C++. SOM is designed to support many languages (although in this first release it supports only C). Rather than a language, SOM is really a system for defining, manipulating, and releasing class libraries. SOM is used to define classes and methods, but it is left up to the implementor to choose a language for implementing methods. Most programmers will therefore be able to use SOM quickly without having to learn a new language syntax. C++ provides minimal support for implementation hiding, or encapsulation. C++ class definitions, which must be released to clients, typically include declarations for the private data and methods. This information is, at best, unnecessarily detracting, and at worst, proprietary. In SOM, the client never has to see such implementation details. The client need see only the .sc files, which by definition contain only public information. C++ has limited means of method resolution. SOM offers several alternatives. Like C++, SOM supports offset method resolution, meaning that each method is represented by a method pointer which is set once and for all at compile time. Unlike C++, SOM also offers facilities for resolving methods at run time. Name Lookup resolution allows a client to ask for a pointer to a method by method name. Dispatch resolution allows a client to package parameters at run time for dispatching to a method, a technique which allows SOM to be integrated into interpreted languages, such as Smalltalk. One other interesting difference between SOM and C++ is in their notion of class. In C++, the class declaration is very similar to a structure declaration. It is a compile-time package with no characteristics that have significance at runtime. In SOM, the class of an object is an object in its own right. This object is itself an instantiation of another class, called the metaclass. The class object supports a host of useful methods which have no direct parallels in C++, such as somGetName(), somGetParent(), and somFindMethod(). SUMMARY A new Object Modeling System is introduced in OS/2 2.0. This object model is called The System Object Model, or SOM. SOM is a dynamic object model which can provide useful class information about objects at run time. The goal of SOM is to support the development of class libraries useful by both compiled and interpreted languages. ACKNOWLEDGEMENTS SOM is the work of many people. Mike Conner developed the initial idea and implementation, and continues to lead the overall design of SOM. Andy Martin designed the SOM Class Interface Language, and designed and implemented the class Interface compiler. Larry Raper implemented many features of the run time library and ported SOM to OS/2. Larry Loucks provided close technical tracking and was instrumental in focusing the effort. Early SOM users who contributed much to the evolution of SOM include Nurcan Coskun, Hari Madduri, Roger Sessions, and John Wang. The project is managed by Tony Dvorak. BIBLIOGRAPHY ULippmane Stanley B. Lippman: C++ Primer, Second Edition. Addison-Wesley, Reading, Massachusetts, 1989. USessions, 89e Roger Sessions: Reusable Data Structures for C. Prentice-Hall, Englewood Cliffs, New Jersey, 1989. USessions, 91e Roger Sessions: Class Construction in C and C++, Object-Oriented Programming Fundamentals. Prentice-Hall, Englewood Cliffs, New Jersey, 1991 (in press). USOMe Tentative Title: System Object Model Users Guide. IBM Publication, 1991 (in preparation). UStroustrupe Bjarne Stroustrup: The C++ Programming Language, Second Edition. Addison-Wesley, Reading, Massachusetts, 1991. BIOGRAPHIES Nurcan Coskun, IBM, 11400 Burnet Road, Austin, TX 78758 Nurcan Coskun has a B.S. in Industrial Engineering from Middle East Technical University, an M.S. and a Ph.D. in Computer Science from University of Missouri-Rolla. Her expertise is in integrated programming environments, code generators, incremental compilers, interpreters, language based editors, symbolic debuggers, application frameworks, and language design. She is now working on Object-Oriented programming environments and previously worked on the OS/2 Database Manager. Nurcan can be contacted at nurcan@ausvm1.iinus1.ibm.com Roger Sessions, IBM, 11400 Burnet Road, Austin, TX 78758 Roger Sessions has a B.A. in Biology from Bard College and an M.E.S. in Database Systems from the University of Pennsylvania. He is the author of two books, Reusable Data Structures for C, and Class Construction in C and C++, and several articles. He is working on Object-Oriented programming environments and previously worked with high performance relational databases and Object-Oriented storage systems. Roger can be contacted at sessions@ausvm1.iinus1.ibm.com.
 hobbes.nmsu.edu/download/pub/os2/dev/wps/som_nt.zip
Record updated last time on: 16/05/2019 - 20:20

Translate to...

Add new comment