The System Object Model (SOM) (18/7/2012, Roger Sessions) |
Readme/What's new |
The System Object Model (SOM): A Technology for Language Independent Objects presentation by Roger Sessions. (Sep 1999). |
hobbes.nmsu.edu/download/pub/os2/dev/info/SOM-Roger_Sessions.zip |
local copy
|
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/tools/toolkits/SOMObjects_Toolkit_3-0.zip |
local copy
|
IDL/Java Language Mapping v. 3.0 (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/tools/toolkits/SOMobjectsJavaClient_3-0.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 |
local copy
|
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 |
|
Comments
Martin Iturbide
Tue, 08/08/2023 - 22:28
Permalink
New link:
Add new comment