Questions and answers about SOM: Difference between revisions

From OS2World.Com Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
(2 intermediate revisions by one other user not shown)
Line 1: Line 1:
Questions and answers about SOM
1.1: Are there plans for debugging SOM objects?
 
 
1.1: Are there plans for debugging SOM objects?


response date:  5/30/92
response date:  5/30/92


Although SOM objects are in general multi-lingual (i.e., the instance
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.
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++.


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?
1.2: Does SOM support garbage collection?


response date: 5/30/92
response date: 5/30/92


This is an area of some importance, and we may work on this in the
This is an area of some importance, and we may work on this in the future.
future.


Garbage collection in a multi-language environment is a hard problem,
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.
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
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.
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?
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
response date: 5/30/92


A service or thread that creates an object (which is given to others but
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.
which may later be "deleted") has the responsibility of defining an
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.
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,
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.
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?
1.4: What are the Costs/Benefits of runtime class objects?


response date: 5/30/92
response date: 5/30/92


The cost is minimal, since there will be only one class object, no matter
The cost is minimal, since there will be only one class object, no matter how many of its instances exist.
how many of its instances exist.


The benefits are great, since the class object can respond dynamically to
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.
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
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.
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?
1.5: What are the Costs/Benefits of always requiring derivation from
SOMObject class?


response date: 5/30/92
response date: 5/30/92


There is no cost, since SOMObject introduces no instance variables.
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,
But there are many benefits, since this allows us to provide important functionality for all SOM objects.
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.


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?
1.6: What SOM Class libraries are there?


response date: 5/30/92
response date: 5/30/92


Currently the Workplace Shell and the SOM run-time classes are
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.
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?
2.1: What are the SOM method resolution mechanisms?


response date: 5/30/92
response date: 5/30/92


Offset resolution is based on knowing a SOM object type that includes the
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.
desired method, and using this knowledge to access a corresponding
Language bindings based on static information declared using OIDL are used to hide the details of this procedure.
"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.
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 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
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.
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
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).
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
The different kinds of method resolution techniques thus correspond to successively greater uncertainty about the class of an object and the methods it supports.
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
In the case of offset resolution, we have an OIDL declaration for a class that includes the desired method.
that includes the desired method.


In the case of name resolution, we don't have a static type for the
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.
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
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.
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
response date: 5/30/92


Name Resolution method :
Name Resolution method:


SOMClass has a method called "somFindMethod". By using this interface it
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.
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 :
Dispatch Resolution:


This mechanism in SOM is created to support dynamic languages. SOMObject
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)
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:
Example program:


student.csc file:
student.csc file:
=================
<code>
 
   include <somobj.sc>
   include <somobj.sc>
 
   class:
   class:
     Student;
     Student;
 
   -- "Student" class provides a base class to generate more specialized
   -- "Student" class provides a base class to generate more specialized
   -- students like "GraduateStudent" and "UnderGraduateStudent".
   -- students like "GraduateStudent" and "UnderGraduateStudent".
   -- Some of the methods like "printStudentInfo" and "getStudentType"
   -- Some of the methods like "printStudentInfo" and "getStudentType"
   -- must be overridden in the subclasses.
   -- must be overridden in the subclasses.
 
   parent:
   parent:
     SOMObject;
     SOMObject;
 
   data:
   data:
     char  idU16e;      /* student id */
     char  idU16e;      /* student id */
     char  nameU32e;    /* student name */
     char  nameU32e;    /* student name */
 
   methods:
   methods:
     override  somInit;
     override  somInit;
 
     void  setUpStudent(char *id, char *name);
     void  setUpStudent(char *id, char *name);
     -- sets up a new student.
     -- sets up a new student.
 
     void  printStudentInfo();
     void  printStudentInfo();
     -- prints the student information.
     -- prints the student information.
 
     char  *getStudentType();
     char  *getStudentType();
     -- returns the student type.
     -- returns the student type.
 
     char  *getStudentId();
     char  *getStudentId();
     -- returns the student id.
     -- returns the student id.
 
</code>
student.c file:
student.c file:
===============
<code>
 
   #define Student_Class_Source
   #define Student_Class_Source
   #include "student.ih"
   #include "student.ih"
 
   SOM_Scope void  SOMLINK somInit(Student *somSelf)
   SOM_Scope void  SOMLINK somInit(Student *somSelf)
   {
   {
Line 230: Line 130:
       _idU0e = _nameU0e = ' ';
       _idU0e = _nameU0e = ' ';
   }
   }
 
   SOM_Scope void  SOMLINK setUpStudent(Student *somSelf,
   SOM_Scope void  SOMLINK setUpStudent(Student *somSelf,
                                         char *id, char *name)
                                         char *id, char *name)
Line 238: Line 138:
       strcpy(_name, name);
       strcpy(_name, name);
   }
   }
 
   SOM_Scope void  SOMLINK printStudentInfo(Student *somSelf)
   SOM_Scope void  SOMLINK printStudentInfo(Student *somSelf)
   {
   {
Line 246: Line 146:
       printf("    Type      : %s 0, _getStudentType(somSelf));
       printf("    Type      : %s 0, _getStudentType(somSelf));
   }
   }
 
   SOM_Scope char *  SOMLINK getStudentType(Student *somSelf)
   SOM_Scope char *  SOMLINK getStudentType(Student *somSelf)
   {
   {
Line 253: Line 153:
       return (type);
       return (type);
   }
   }
 
   SOM_Scope char *  SOMLINK getStudentId(Student *somSelf)
   SOM_Scope char *  SOMLINK getStudentId(Student *somSelf)
   {
   {
Line 259: Line 159:
       return (_id);
       return (_id);
   }
   }
 
</code>
Client program:
Client program:
===============
<code>
 
   #include "student.h"
   #include "student.h"
 
   sendMessage(char *method, SOMObject *target, char *str1, char
   sendMessage(char *method, SOMObject *target, char *str1, char *str2)
  *str2)
   {
   {
       somMethodProc *methodPtr;
       somMethodProc *methodPtr;
 
       _somFindMethod(_somGetClass(target),
       _somFindMethod(_somGetClass(target),
           somIdFromString(method), &methodPtr);
           somIdFromString(method), &methodPtr);
       (*methodPtr)(target,str1, str2);
       (*methodPtr)(target,str1, str2);
   }
   }
 
   dispatchMessage(char *method, SOMObject *target, ...)
   dispatchMessage(char *method, SOMObject *target, ...)
   {
   {
Line 282: Line 180:
     va_end(ap);
     va_end(ap);
   }
   }
 
   main()
   main()
   {
   {
Line 288: Line 186:
     Student *student2 = StudentNew();
     Student *student2 = StudentNew();
     Student *student3 = StudentNew();
     Student *student3 = StudentNew();
 
     _setUpStudent(student1, "599600", "David Brown");
     _setUpStudent(student1, "599600", "David Brown");
     sendMessage("setUpStudent", student2, "120045", "Janet Smith");
     sendMessage("setUpStudent", student2, "120045", "Janet Smith");
Line 296: Line 194:
     _printStudentInfo(student3);
     _printStudentInfo(student3);
   }
   }
 
</code>
Output from this program:
Output from this program:
=========================
<code>
 
     Id        : 599600
     Id        : 599600
     Name      : David Brown
     Name      : David Brown
     Type      : student
     Type      : student
 
     Id        : 120045
     Id        : 120045
     Name      : Janet Smith
     Name      : Janet Smith
     Type      : student
     Type      : student
 
     Id        : 789001
     Id        : 789001
     Name      : Maria Somer
     Name      : Maria Somer
     Type      : student
     Type      : student
 
</code>
 
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
2.2: What might language bindings for C++ look like? Because SOM seems
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?
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
response date: 5/30/92


SOM is not a programming language, and does not attempted to support all
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.
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
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.
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
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.
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.


The purpose of C++ bindings for SOM would be to make it easy for a C++
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
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
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.
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
Subclassable is based on C++ instance data that holds a pointer to a wrapped SOM object, and uses a C++ virtual function table.
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
Either approach could be supported by a special C++ compiler front-end, which would provide the corresponding functionality, while optimizing performance.
wrapped SOM object, and uses a C++ virtual function table.


Either approach could be supported by a special C++ compiler front-end,
What are the functionalities associated with (1) and (2)?
which would provide the corresponding functionality, while optimizing
performance.


What are the functionalities associated with (1) and (2) ?
With (1), Instantiable:


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).


All SOM objects (including class objects) are available to a C++
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.
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
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).
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++
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).
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
With (2), Subclassable:
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.


As with the Instantiable approach, SOM objects (including classes) are
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.
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
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.
(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
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.
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,
2.3: How about inter-process method calls?
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
response date: 5/30/92


This capability is planned. Currently, SOM can be used with shared
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).
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)?
2.4: Will SOM and the WPS be supported on multiple platforms (other than AIX)?


response date: 6/1/92
response date: 6/1/92


We're working on getting SOM available on AIX. As for the WPS, we don't
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.
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?
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
response date: 5/30/92


To allow a given language to use and define class of SOM objects, we
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.
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
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.
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.


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?
2.6: How does SOM implement language independence?


response date: 5/30/92
response date: 5/30/92


Discussion of language independence in SOM ultimately relates to the
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).
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
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.
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
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.
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
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.
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
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.
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.


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
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?
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
response date: 6/10/92


This would not a problem at all with C++ bindings (since C++ classes
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).
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.


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.
<code>
   #include "A.h"
   #include "A.h"
   #undef _foo
   #undef _foo
   #include "B.h"
   #include "B.h"
   #undef _foo
   #undef _foo
 
   void test(A *a, B *b)
   void test(A *a, B *b)
   {
   {
Line 584: Line 309:
     B_foo(b,12); /* instead of _foo(b,12) */
     B_foo(b,12); /* instead of _foo(b,12) */
   }
   }
</code>
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.


The only important thing is this:  if you see a warning that a method
Again Note: The C++ bindings would not have this problem, because they would not be based on macros, but, instead, inline C++ method expansions.
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
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.
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
response date: 6/10/92


First off, this should not be a surprise to anyone familiar with C++,
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.
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?
Why is it necessary in SOM, though?


As in C++, it is required for implementing inheritance of interface. The
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.
method invocation macros that support the methods introduced by any given
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.
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?
3.3: Why isn't access to data inherited?


response date: 6/10/92
response date: 6/10/92


First it is necessary to understand that the SOM API does allow direct
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.
(uninterpreted, offset-based) access to the instance variables of SOM
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:
objects. As a matter of policy, however, the usage bindings for SOM
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.
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
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.
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.
The following are two reasons for our approach.


(1) SOM is intended to support arbitrary languages, allowing a subclass
(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.
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
(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.
objective is that changing the implementation for a class of objects
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.
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.
3.4: Is the interface to published methods a macro or a function.


response date: 6/10/92
response date: 6/10/92


Just as with access to instance data, access to the procedure that
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.
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.


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
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.
<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
response date: 6/10/92


The underscore form of the macro is certainly not intended for use by
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.
class clients. It is defined within the usage bindings solely to support
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.
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?
4.1: Is there a version of SOM that is OMG (CORBA) compliant?


response date: 6/12/92
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.
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"?
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
response date: 6/30/92
Line 745: Line 369:
;Instantiable
;Instantiable


First of all, with the "Instantiable" approach, it is not necessary to
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.
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
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
would (1) use OIDL to declare a new SOM class whose parent is WPAbstract,
can be seen, this is essentially the same approach used for the C implementation bindings.
(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.
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.
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.
Line 764: Line 380:
;Subclassable
;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.
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.


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.
[[Category:Development]]

Revision as of 16:01, 2 April 2021

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.