Object-Oriented Programming in OS/2 2.0 by Roger Sessions Nurcan Coskun -------------------------------------------------------- Author Contact Information Roger Sessions AUSVM1(SESSIONS) tieline 678-8085 Nurcan Coskun AUSVM1(NURCAN) tieline 678-8073 -------------------------------------------------------- IBM Personal Systems Developer, Winter 1991, Copyright 1991 by INTERNATIONAL BUSINESS MACHINES CORPORATION. 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 [Sessions, 89]. 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 *stackArray[STACK_SIZE]; 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->stackArray[thisStack->stackTop] = 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 [SOM]. 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 class: Student; -- "Student" class provides a base class to generate more -- specialized students like "GraduateStudent" and -- "UnderGraduateStudent". parent: SOMObject; data: char id[16]; /* student id */ char name[32]; /* 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 [SOM]. 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 class: GraduateStudent; parent: Student; data: char thesis[128]; /* thesis title */ char degree[16]; /* 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 class: UnderGraduateStudent; parent: Student; data: char date[16]; /* 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 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 code[8]; /* course code number */ char title[32]; /* course title */ char instructor[32]; /* instructor teaching */ int credit; /* number of credits */ int capacity; /* maximum number of seats */ Student *studentList[20];/* 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 #include "course.ih" static void somInit(Course *somSelf) { CourseData *somThis = CourseGetData(somSelf); parent_somInit(somSelf); _code[0] = _title[0] = _instructor[0] = '\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); _studentList[_enrollment++] = 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(_studentList[i]))) { _enrollment--; for(i; i<_enrollment; i++) _studentList[i] = _studentList[i+1]; 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(_studentList[i]); 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 #include #include #include 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++ [Sessions, 91], The C++ Programming Language [Stroustrup], and C++ Primer [Lippman]. 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++ [Sessions, 91]. 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 [Lippman] Stanley B. Lippman: C++ Primer, Second Edition. Addison-Wesley, Reading, Massachusetts, 1989. [Sessions, 89] Roger Sessions: Reusable Data Structures for C. Prentice-Hall, Englewood Cliffs, New Jersey, 1989. [Sessions, 91] Roger Sessions: Class Construction in C and C++, Object-Oriented Programming Fundamentals. Prentice-Hall, Englewood Cliffs, New Jersey, 1991 (in press). [SOM] Tentative Title: System Object Model Users Guide. IBM Publication, 1991 (in preparation). [Stroustrup] 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.