Questions and answers about SOM: Difference between revisions

From OS2World.Com Wiki
Jump to navigation Jump to search
(Created page with "Questions and answers about SOM 1.1: Are there plans for debugging SOM objects? response date: 5/30/92 Although SOM objects are in general multi-lingual (i.e., the inst...")
 
No edit summary
Line 181: Line 181:
  vice versa)
  vice versa)


Example program:
Example program:
================


  student.csc file:
  student.csc file:
Line 457: Line 456:




2.4:  Will SOM and the WPS be supported on multiple platforms (other
2.4:  Will SOM and the WPS be supported on multiple platforms (other than AIX)?
than AIX)?


response date: 6/1/92
response date: 6/1/92
Line 468: Line 466:


2.5:  What does it take for another language to be supported under SOM?
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
Once a language is supported, does this mean that any standard compiler for that language will do?
for that language will do?


response date: 5/30/92
response date: 5/30/92
Line 693: Line 690:
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
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
are very similar.  To access data (using the SOM API directly), one calls
somDataResolve passing an object and a data token.  To access the
somDataResolve passing an object and a data token.  To access the
procedure that supports a method, one calls somResolve passing an object
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
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
"logical" offsets.  They provide a very fast way of accessing the desired
information, and are statically available via usage bindings.  As with
information, and are statically available via usage bindings.  As with
data access, usage bindings try to hide the details.  In the C bindings,
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
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
defining C++ methods as expanded inline.  The result is the same, since
the same function call is compiled inline in both cases.
the same function call is compiled inline in both cases.


In drastic contrast, name lookup first requires getting the class of the
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.
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
This is rather more expensive than simply retrieving a method token from
a known, globally available location (which is what the usage bindings do
a known, globally available location (which is what the usage bindings do
for static method invocations).  Once the method token is available,
for static method invocations).  Once the method token is available,
somResolve is used to return a pointer to the procedure that supports the
somResolve is used to return a pointer to the procedure that supports the
desired method on the object.
desired method on the object.




Line 721: Line 718:
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
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
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
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
for method invocation starts with an underscore, and a SOM user thus
might forget and use the underscore when requesting instance creation.
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
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
longer defined defined.)  In general, the macro-based C usage bindings
are open to a number of similar criticisms.  The C++ bindings would not
are open to a number of similar criticisms.  The C++ bindings would not
suffer from this problem, since they would not be macro-based.
suffer from this problem, since they would not be macro-based.




Line 737: Line 734:
response date: 6/12/92
response date: 6/12/92


We are currently working upon a CORBA compliant version of SOM.  This
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.
will include an IDL compiler (with suitable enhancements to accept SOM
Class Implementation details) and all SOM runtime classes in IDL.




Line 748: Line 743:
response date: 6/30/92
response date: 6/30/92


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
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
WPAbstract using C++.  All that is needed is an OIDL class description
(e.g., the .sc file) for WPAbstract.
(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,
would (1) use OIDL to declare a new SOM class whose parent is WPAbstract,
(2) generate Instantiable C++ implementation bindings for the resulting
(2) generate Instantiable C++ implementation bindings for the resulting
subclass, and (3) fill out the resulting default method procedure
subclass, and (3) fill out the resulting default method procedure
templates for overridden and newly-introduced methods with C++ code.  As
templates for overridden and newly-introduced methods with C++ code.  As
can be seen, this is essentially the same approach used for the C
can be seen, this is essentially the same approach used for the C
implementation bindings.
implementation bindings.


How is this different from using C implementation bindings to implement a
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.
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
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.
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
;Subclassable
============


With the Subclassable approach, a C++ programmer would use a C++ class
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.
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
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.
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.

Revision as of 05:07, 9 November 2020

Questions and answers about SOM


1.1: Are there plans for debugging SOM objects?

response date: 5/30/92

Although SOM objects are in general multi-lingual (i.e., the instance
variables and method procedures encapsulated by an object may be
implemented by different languages), the newly introduced instance
variables and methods for each derived class of SOM objects are always
implemented by a single language, and the API for class creation can
include specification of this language.  Thus, the information necessary
to invoke the correct debugger for tracing through individual methods can
be made available.  This suggests the possibility of providing a
framework within which different debuggers can be dynamically called to
trace method calls as execution proceeds.
Currently, we use C language debuggers for debugging SOM classes
implemented using C. As they become available, we may use C++ debuggers
for SOM classes implemented using C++.


1.2: Does SOM support garbage collection?

response date: 5/30/92

This is an area of some importance, and we may work on this in the
future.
Garbage collection in a multi-language environment is a hard problem,
though.  Even the single language case is not straightforward; take the
problem of automatic garbage collection for C language programs, for
example.
But it is possible that enhancements to the current SOM API might be able
to provide information upon which a GC capability could be based.


1.3: If SOM doesn't provide GC, then is there SOM support for freeing objects when multiple threads have access to them?

response date: 5/30/92

A service or thread that creates an object (which is given to others but
which may later be "deleted") has the responsibility of defining an
appropriate protocol for client registration to support the object's use.
SOM doesn't provide any specific support for this.  Critical regions, for
example, are provided by the usual operating system interfaces; not
through any primitive SOM objects or classes.
It should be possible to provide such facilities through SOM classes,
allowing inheritance to provide uniform support of protocols.  Although
such classes are not provided by the basic SOM runtime, they can be
provided as application frameworks.


1.4: What are the Costs/Benefits of runtime class objects?

response date: 5/30/92

The cost is minimal, since there will be only one class object, no matter
how many of its instances exist.
The benefits are great, since the class object can respond dynamically to
requests concerning object and class information that is only known at
runtime.  In addition, specializations of SOMClass can create metaclasses
that provide additional facilities, or override SOMClass methods to
provide tailored behavior for classes of objects.
Since class objects are created at runtime, it is even possible to
support adaptable systems in which the desired classes of objects may be
discovered or may change as the system evolves.  In advanced, interactive
systems, the ability to create "new" kinds of objects in response to
changing circumstances can be useful.


1.5: What are the Costs/Benefits of always requiring derivation from SOMObject class?

response date: 5/30/92

There is no cost, since SOMObject introduces no instance variables.
But there are many benefits, since this allows us to provide important
functionality for all SOM objects.
As an example of useful functionality, every SOM object knows its class,
and can return its class object.  Also, SOMObject methods allow
introducing defaults for routines (like dumpSelf) that can be specialized
by individual classes.  There are other, deeper examples as well, related
to support for dynamic method dispatching.


1.6: What SOM Class libraries are there?

response date: 5/30/92

Currently the Workplace Shell and the SOM run-time classes are
available for use on OS/2.  Various additional class libraries are
planned for the future that cover topics such as replication,
persistance, event management, GUI, CORBA Interface Repository,
foundation classes, etc.


2.1: What are the SOM method resolution mechanisms?

response date: 5/30/92

Offset resolution is based on knowing a SOM object type that includes the
desired method, and using this knowledge to access a corresponding
"method token" from a global data structure.  The object and the method
token are passed to somResolve (the SOM procedure for offset method
resolution), and the appropriate procedure pointer is returned.  This
pointer is then used to invoke the procedure and perform the method.
Language bindings based on static information declared using OIDL are
used to hide the details of this procedure.
Name resolution is based on knowing the arguments for a desired method.
The method name is passed to the somFindMethod method of the object's
class object, and the result is the appropriate procedure pointer.  Name
resolution is available for any SOM object, irrespective of its class.
This is because offset resolution can be used on any object to find it's
class object (the somGetClass method is in the SOMObject type), and can
then be used on the resulting class object to do name resolution (the
somFindMethod is in the SOMClass type).
The two methods above assume that it is possible to statically construct
within a program a procedure call that applies the "resolved" procedure
pointer to the appropriate arguments -- either explicitly, within code
written by the programmer, or implicitly, within "language bindings."  If
the programming language does not support procedure pointers, or the
appropriate arguments are not known until runtime, then dispatch
resolution can be used.
Dispatch resolution accepts as parameters a method name and a
dynamically constructed argument list (class objects can be used to
discover what the appropriate arguments for a method call are), and is
available as an offset method call on all objects (since the dispatch
methods are included in the SOMObject type).
The different kinds of method resolution techniques thus correspond to
successively greater uncertainty about the class of an object and the
methods it supports.
In the case of offset resolution, we have an OIDL declaration for a class
that includes the desired method.
In the case of name resolution, we don't have a static type for the
object more specific than, often, SOMObject.  But knowing only this type,
we are able to use offset resolution to access the object's class, check
whether the object supports a desired method (whose arguments we know),
and then call the appropriate procedure.
In the case of dispatch resolution, we can't use offset resolution
because we don't have an appropriate type for the object, and we can't
use name resolution because we don't know what the appropriate arguments
are.  But, as described above, the information required for dispatch
resolution is always available dynamically.

response date: 5/30/92

Name Resolution method :
SOMClass has a method called "somFindMethod".  By using this interface it
is possible to get a method pointer if the object supports the specified
method.  This method pointer can be used to make a dynamic method call.
It is a useful mechanism for optimization.  Another application is that
if the only information about the method call is its signature, we could
use this to make the method call.
Dispatch Resolution :
This mechanism in SOM is created to support dynamic languages.  SOMObject
provides "somDispatch" interfaces which can be overridden by providing
dynamic-language supported "somDispatch" routines.  "somDispatch"
interfaces accepts a variable argument list for the method parameters.
Dynamic languages can construct a variable argument list and use this
interface to send messages to SOM objects.  (we use this mechanism to
support subclassing of SOM classes in OREXX, Object-Oriented REXX, and
vice versa)

Example program:

student.csc file:
=================
 include <somobj.sc>
 class:
   Student;
 -- "Student" class provides a base class to generate more specialized
 -- students like "GraduateStudent" and "UnderGraduateStudent".
 -- Some of the methods like "printStudentInfo" and "getStudentType"
 -- must be overridden in the subclasses.
 parent:
   SOMObject;
 data:
   char  idU16e;      /* student id */
   char  nameU32e;    /* student name */
 methods:
   override  somInit;
   void  setUpStudent(char *id, char *name);
   -- sets up a new student.
   void  printStudentInfo();
   -- prints the student information.
   char  *getStudentType();
   -- returns the student type.
   char  *getStudentId();
   -- returns the student id.
student.c file:
===============
 #define Student_Class_Source
 #include "student.ih"
 SOM_Scope void   SOMLINK somInit(Student *somSelf)
 {
     StudentData *somThis = StudentGetData(somSelf);
     parent_somInit(somSelf);
     _idU0e = _nameU0e = ' ';
 }
 SOM_Scope void   SOMLINK setUpStudent(Student *somSelf,
                                       char *id, char *name)
 {
     StudentData *somThis = StudentGetData(somSelf);
     strcpy(_id, id);
     strcpy(_name, name);
 }
 SOM_Scope void   SOMLINK printStudentInfo(Student *somSelf)
 {
     StudentData *somThis = StudentGetData(somSelf);
     printf("   Id         : %s 0, _id);
     printf("    Name       : %s 0, _name);
     printf("    Type       : %s 0, _getStudentType(somSelf));
 }
 SOM_Scope char *  SOMLINK getStudentType(Student *somSelf)
 {
     StudentData *somThis = StudentGetData(somSelf);
     static char *type = "student";
     return (type);
 }
 SOM_Scope char *  SOMLINK getStudentId(Student *somSelf)
 {
     StudentData *somThis = StudentGetData(somSelf);
     return (_id);
 }
Client program:
===============
 #include "student.h"
 sendMessage(char *method, SOMObject *target,  char  *str1,  char
 *str2)
 {
     somMethodProc *methodPtr;
     _somFindMethod(_somGetClass(target),
         somIdFromString(method), &methodPtr);
     (*methodPtr)(target,str1, str2);
 }
 dispatchMessage(char *method, SOMObject *target, ...)
 {
   va_list ap;
   va_start(ap, target);
   SOMObject_somDispatchV(target, somIdFromString(method), "", ap);
   va_end(ap);
 }
 main()
 {
    Student *student1 = StudentNew();
    Student *student2 = StudentNew();
    Student *student3 = StudentNew();
    _setUpStudent(student1, "599600", "David Brown");
    sendMessage("setUpStudent", student2, "120045", "Janet Smith");
    dispatchMessage("setUpStudent", student3, "789001", "Maria Somer");
    _printStudentInfo(student1);
    _printStudentInfo(student2);
    _printStudentInfo(student3);
 }
Output from this program:
=========================
    Id         : 599600
    Name       : David Brown
    Type       : student
    Id         : 120045
    Name       : Janet Smith
    Type       : student
    Id         : 789001
    Name       : Maria Somer
    Type       : student


2.2: What might language bindings for C++ look like? Because SOM seems to omit a large subset of C++ constructs, it seems that C++ bindings may be little more than the current C bindings, save maybe the hassle of dealing with the 'this' pointer. Is this true? Will I have to give up exception handling, templates, default method arguments, operator overloading, etc..?? Will I just be basically coding in C, but compiling with C++? If these kinds of features will be available under the C++ support, will I have to use convoluted macros, or will I be able to code using the C++ semantics? If a construct is supported under one SOM language binding, will all other language bindings also have to support it? Why not make the SOM OIDL a superset of the functions provided by the popular OO languages, with some neat SOM bonus features?

response date: 5/30/92

SOM is not a programming language, and does not attempted to support all
of the features of all object-oriented languages.  This is probably
impossible and self-contradictory.  SOM does provide an extremely
flexible and powerful framework for advanced object-oriented systems
development.  The central focus and contribution of SOM is support for
binary distribution of language-neutral class libraries.  In contrast,
language-centric class libraries are limited in utility (they are useful
only from a single language), and require publication of source code
(different compilers for the same object-oriented language cannot be
guaranteed to use the same object layouts in memory, so a binary class
library produced by one compiler will generally be useless to
applications developed with a different compiler).  SOM solves these
problems.
In general, we don't expect that SOM will be used to implement all of the
objects and classes important to an application.  Many objects created
and used by an application will be strictly internal to that
application's implementation -- with no need for being accessed by
multiple languages or applications.  Perhaps these internal objects will
be SOM objects (in those cases where a SOM class library provides useful
functionality), or perhaps they will be objects provided by some other
class library (e.g., a Smalltalk or C++ class library), depending on the
language used to program the application.
Only objects whose implementation is to be provided or used by
non-object-oriented programming languages, or objects intended to be
useful across application and language boundaries with upwards binary
compatability need to be SOM objects.  We believe such objects can be
valuable; supporting such objects is SOM's objective.
---
The purpose of C++ bindings for SOM would be to make it easy for a C++
programmer to use SOM objects, and to make it easy for a C++ programmer
to define new SOM object classes.
There are many ways of accomplishing these two goals.  We have identified
at least three different approaches to C++ bindings, which may be
characterized as follows:  (1) Instantiable (2) Subclassable (3)
Compiler-Supported
Instantiable is based on in-line expansion of C++ method calls into SOM
offset resolution method calls.  The approach requires no C++ instance
data, since the pointer to a C++ object that "wraps" a SOM object IS the
pointer to the wrapped SOM object.
Subclassable is based on C++ instance data that holds a pointer to a
wrapped SOM object, and uses a C++ virtual function table.
Either approach could be supported by a special C++ compiler front-end,
which would provide the corresponding functionality, while optimizing
performance.
What are the functionalities associated with (1) and (2) ?
With (1), Instantiable:
All SOM objects (including class objects) are available to a C++
programmer as C++ objects of a corresponding C++ class.  Such SOM objects
can be created using the C++ "new" operation on the C++ class name.  The
SOM class hierarchy is faithfully mirrored in the C++ class hierarchy.
As a result, the C++ compiler provides static typechecking for SOM object
use.  A C++ programmer using the SOM bindings to access SOM objects thus
has access to all of C++ in his code.  (The important qualification here
is the use of the word "object" instead of the word "class" -- see the
next paragraph).
If it is desired to implement an OIDL-specified class using C++, an OIDL
specification for the desired SOM class is provided as input to the SOM
compiler, and C++ implementation bindings for the class are generated and
used by the C++ programmer.  The C++ programmer uses (unrestricted) C++
code to implement procedures supporting the newly-introduced methods of
the class.  Thus, individual C++ procedures (not C++ methods) are defined
to support the methods introduced and overridden by the OIDL- specified
class.
Of course, using "this" within such procedures is meaningless.  The C++
methods in which "this" is used contain the (inline) SOM offset
resolution method calls that are used to invoke the supporting
procedures.  The primary difference from the C implementation bindings is
that the new class can introduce C++ instance variables (including C++
objects), and the method procedures used to implement new and overridden
methods can make use of local C++ variables (again, including C++
objects).
Thus, subclassing is done in OIDL -- not C++ -- and all parent classes
must themselves be SOM classes.  The C++ classes that mirror SOM classes,
and whose instances are actually SOM objects, cannot be subclassed in
C++.  Only the mirrored SOM classes themselves can be subclassed (using
OIDL and some choice of implementation bindings).
With (2), Subclassable:
As with the Instantiable approach, SOM objects (including classes) are
available to a C++ programmer as an instance of a C++ class, and the SOM
class hierarchy is faithfully mirrored in the C++ class hierarchy.  As a
result, the C++ compiler provides static typechecking for SOM object use.
But subclassing can now be done in C++.  A C++ subclass can be derived
(in C++) from the C++ representative of a SOM class, and can introduce
new instance variables and methods, and override inherited methods.  This
allows a new C++ class to be derived from both C++ and SOM classes.
Unfortunately, using language bindings to allow C++ to override inherited
SOM methods and pass C++ objects as arguments to SOM methods introduces
performance penalties.  Some of these can be avoided in a
compiler-supported approach.
Using a dual approach, C++ classes can be made available as SOM class,
through an interface that provides the SOM benefits.  Again, there are
performance tradeoffs.


2.3: How about inter-process method calls?

response date: 5/30/92

This capability is planned.  Currently, SOM can be used with shared
memory for this purpose (this is not a supported capability, but some
users are doing it).  But SOM is being enhanced to support the CORBA
standards for object method invocation in a distributed open system
environment.  As an initial step in this directions, we will be
supporting calls across address spaces on a single machine.  Also,
classes being developed as class libraries may provide automated support
for replicated objects across address spaces (i.e., one "logical" object;
many "physical" copies).


2.4: Will SOM and the WPS be supported on multiple platforms (other than AIX)?

response date: 6/1/92

We're working on getting SOM available on AIX.  As for the WPS, we don't
know if there are plans or a desire to put it on AIX.  As for other
platforms for SOM, there don't appear to be any technical barriers.


2.5: What does it take for another language to be supported under SOM? Once a language is supported, does this mean that any standard compiler for that language will do?

response date: 5/30/92

To allow a given language to use and define class of SOM objects, we
decide how to map the types and objects of SOM into this other language.
There may be many ways to do this; we decide on one, and then write
emitters that automate the process.  Then all that is needed is a
standard compiler for the language, plus use of the emitters to produce
SOM class bindings.  This has currently been done for C and C++.  We are
working on other languages as well.
The above approach assumes that it is possible to make use of the SOM API
from within the language for which bindings are desired.  The SOM API was
designed with the desire to require as little as possible for its use.
The SOM API basically requires the ability to make external procedure
calls using system-defined linkage, and the ablity to construct simple
data structures in memory.
Where these capabilities are available at the language level, SOM
bindings can be source level; where they are not, SOM bindings will
require compiler support, in addition to any source-level bindings that
might be used.


2.6: How does SOM implement language independence?

response date: 5/30/92

Discussion of language independence in SOM ultimately relates to the
ability of different languages to use SOM objects and define new SOM
classes (which, really, is simply a use of SOM objects).
It is not SOM's most direct purpose to allow C++ programmers to invoke
virtual functions on Smalltalk objects, or allow C++ to subclass
Smalltalk classes.  SOM does allow both C++ and Smalltalk (as well as
other languages) to use SOM objects and to implement new classes of SOM
objects by inheriting and enhancing the implementation of other classes
of SOM objects.  As a result of this capability, SOM does reduce an order
n-squared interface problem to an order n interface problem.  In
addition, SOM does provide facilities that are useful in this reguard.
Multi-language capability is a primary objective for SOM.  Achieving this
objective has influenced SOM's design in many ways, so there is no single
answer to this question.  As we produce new language bindings for SOM, we
are likely to iterate the SOM design (while maintaining binary capability
with previous versions) to provide better support for this.
The SOM API for invoking methods on SOM objects is ultimately based on
calls to external procedures defined by the SOM runtime, a small set of
simple types (including pointers to data and pointers to procedures) and
few simple data structures.  Any languages with these capabilities can
use SOM directly.  Where these facilities are not available directly at
the language level, it is possible they might be provided by "helper
functions," provided by a compiler-specific procedure library, or they
might be directly supported by compiler modifications.
When a given language is used to implement a new SOM class, the instance
variables that are introduced, and the procedures used to support
introduced and overridden methods need not be useful (or comprehensible)
to the languages used to implement subsequently derived classes.  This is
one reason why SOM does not allow inherited access to instance variables.
As a result, multi-language objects are possible, in which instance
variables and method procedures are contributed by different programming
languages.  When a method is invoked on a SOM object, the appropriate
procedure is called, and this procedure then can directly access only
those instance variables that were introduced by the class the procedure
supports.
For obvious reasons, we have initially focused on the cases in which the
SOM API is useful without compiler-specific support.  But as interest in
SOM grows, it is likely that we will also be investigating other
possibilities.  Due to the simplicity of the SOM API, compiler
modifications necessary for its support should be straightforward.  For
example, a compiler vendor for a non- object-oriented language without
the ability to directly use the SOM API might consider the ability to use
SOM objects a strategic advantage worth the small effort involved in
providing this capability through compiler modifications.


3.1: Is there a problem when two unrelated classes introduce methods of the same name, and a client code wants to deal with objects of both classes? What if the methods take a different number of arguments?

response date: 6/10/92

This would not a problem at all with C++ bindings (since C++ classes
provide method scoping).  The C bindings for SOM, however, are based on
macros, so method "collision" in this case, as a result of different
macros being #included into C source that deals with different classes of
objects, is something that can happen.  When this does happen, however,
it is not a serious problem (it is an annoyance, and the following
describes how to deal with it).
In the C bindings, corresponding to any given method on a SOM object are
two different invocation macros:  a "short" form in which the macro name
contains only the method name (e.g., _foo for the method foo); and a
"long" form, in which the macro name includes both the class that
introduced the method and, in addition, the method name.  Certainly, if
class A and class B both define a foo method, and some client code
includes both A.h and B.h, then the short forms of the macros will
"collide."  This is will result in either warning messages or error
messages -- depending on the particular C compiler being used.  For
example, assume that the foo method available on A instances was
introduced by the class, Z, an ancestor of A, and that the foo method
available on B instances was introduced by the class, B. Then the
following code should be used.
 #include "A.h"
 #undef _foo
 #include "B.h"
 #undef _foo
 void test(A *a, B *b)
 {
   Z_foo(a);    /* instead of _foo(a) */
   B_foo(b,12); /* instead of _foo(b,12) */
 }
The only important thing is this:  if you see a warning that a method
invocation macro has been redefined, then it is absolutely essential that
the long form of the method invocation macros be used.  Note that in the
above example, the methods take different numbers of arguments, as in
your question.  The #undef's prevent the warning (or error) messages, and
also prevent accidental use of the short form.
Again Note:  The C++ bindings would not have this problem, because
they would not be based on macros, but, instead, inline C++ method
expansions.


3.2: Why do the usage bindings for a class automatically include usage bindings for its parent (which, in turn include the usage bindings for its parent, and so on until SOMObject is reached)? The result is that if a client includes the usage bindings for a given class, then the usage bindings for all of that class's ancestors are included as well.

response date: 6/10/92

First off, this should not be a surprise to anyone familiar with C++,
since any client of a C++ class must include the class's structure
definition, and defining a class's structure can only be done after
defining the structure of the parent classes.  So a very similar sort of
chaining effect occurs in within any code that uses a C++ class.
Why is it necessary in SOM, though?
As in C++, it is required for implementing inheritance of interface.  The
method invocation macros that support the methods introduced by any given
class initially appear in the usage bindings for the introducing class,
and these must be "inherited" by the usage bindings for classes derived
from this class.  Also, to actually accomplish a static method call
ultimately requires to evaluate an expression that accesses the ClassData
structure of the class that introduced the method.  And this data
structure is defined in the usage bindings for the introducing class.
If, for example, the usage bindings for SOMObject were not included by
some derived class's usage bindings, then none of the methods introduced
by SOMObject would be available statically on instances of the derived
class.


3.3: Why isn't access to data inherited?

response date: 6/10/92

First it is necessary to understand that the SOM API does allow direct
(uninterpreted, offset-based) access to the instance variables of SOM
objects.  As a matter of policy, however, the usage bindings for SOM
classes do not automatically provide an interface to this capability.
Some reasons for this explained below.  However, the SOM API is always
available directly to users, so direct access to instance variables is
possible if an application is willing to suffer the consequences:
changes in implementation of the class whose introduced instance
variables are accessed may require recompilation of the application's
source code.  Within tightly-coupled "friend" classes, this may be
reasonable.
SOM simply doesn't provide this facility as a default.  Instead, SOM
provides a machanism whereby a SOM class developer decides which instance
variables introduced by that class should be visible to clients, and for
these instance variables (and only these) is an interface provided by the
usage bindings for that class.
The following are two reasons for our approach.
(1) SOM is intended to support arbitrary languages, allowing a subclass
to be implemented independently of the language(s) used to implement its
ancestor classes.  Typically, a class C implemented using language X will
introduce instance variables to support its methods.  Now, lets say that
language Y is now used to implement a subclass of C named S. S will also
introduce instance variables in support of its methods.  Certainly, the
code that implements these methods should have direct access to the
instance variables that were introduced for its support.  But there is no
reason whatsoever to expect that the instance variables that make sense
to language X (used in support of C's method procedures) will also make
sense to language Y (used in support of S's method procedures).  Given
SOM's desire to support multi-language objects, there seems very little
reason for believing that inherited access to instance variables
introduced by ancestor classes makes sense in general.  Thus, the
procedures that implement methods introduced by a class have direct
access only to those instance variables introduced by the class.
(2) There is another reason related to binary compatibility.  SOM's
objective is that changing the implementation for a class of objects
should not require re-compiling any code that depends on this class.
Code that depends on a class includes both client code, and code that
implements subclasses.  Now, if the code that implements a subclass were
allowed direct access to inherited instance variables, this code would
certainly require recompilation (and more likely, redesign) when
implementation of an ancestor class changes.  SOM does provide access
mechanisms for instance variables, but the decision to "publish" an
instance variable for access by others is a decision of the class
implementor -- not the class user.  So the class implementor knows what
portions of the implementation others could depend on, and what portions
can be changed without concern for users.  As mentioned above, it is
possible to defeat approach, but it must be done with knowledge of the
SOM API -- the language bindings (which hide the API) don't provide
direct support for it.


3.4: Is the interface to published methods a macro or a function.

response date: 6/10/92

Just as with access to instance data, access to the procedure that supports a given method is based on a function call. The two situations are very similar. To access data (using the SOM API directly), one calls somDataResolve passing an object and a data token. To access the procedure that supports a method, one calls somResolve passing an object and a method token. Both data and method tokens can be thought of as "logical" offsets. They provide a very fast way of accessing the desired information, and are statically available via usage bindings. As with data access, usage bindings try to hide the details. In the C bindings, this is done with a macro; in the C++ bindings, this may be done by defining C++ methods as expanded inline. The result is the same, since the same function call is compiled inline in both cases.

In drastic contrast, name lookup first requires getting the class of the object, and then invoking methods on the class to get a method token. This is rather more expensive than simply retrieving a method token from a known, globally available location (which is what the usage bindings do for static method invocations). Once the method token is available, somResolve is used to return a pointer to the procedure that supports the desired method on the object.


3.5: There is a problem with the _<class-name>New macro. Unlike the <class-name>New macro (note no underscore prefix). Using the first may create errors, since it assumes that the class object exists.

response date: 6/10/92

The underscore form of the macro is certainly not intended for use by class clients. It is defined within the usage bindings solely to support the non-underscore form, which is the (only) form documented in the SOM user's guide. This could cause a problem, though, since the short form for method invocation starts with an underscore, and a SOM user thus might forget and use the underscore when requesting instance creation. This has been been fixed. (I.e., the underscore form of the macro is no longer defined defined.) In general, the macro-based C usage bindings are open to a number of similar criticisms. The C++ bindings would not suffer from this problem, since they would not be macro-based.


4.1: Is there a version of SOM that is OMG (CORBA) compliant?

response date: 6/12/92

We are currently working upon a CORBA compliant version of SOM. This will include an IDL compiler (with suitable enhancements to accept SOM Class Implementation details) and all SOM runtime classes in IDL.


5.1: For example, if I had a "C++ binding" for the workplace shell classes, what might a C++ programmer write in order to subclass "WPAbstract"?

response date: 6/30/92

Instantiable

First of all, with the "Instantiable" approach, it is not necessary to have a C++ binding for WPAbstract in order to implement a subclass of WPAbstract using C++. All that is needed is an OIDL class description (e.g., the .sc file) for WPAbstract.

Assuming that the .sc file for WPAbstract is available, a C++ programmer would (1) use OIDL to declare a new SOM class whose parent is WPAbstract, (2) generate Instantiable C++ implementation bindings for the resulting subclass, and (3) fill out the resulting default method procedure templates for overridden and newly-introduced methods with C++ code. As can be seen, this is essentially the same approach used for the C implementation bindings.

How is this different from using C implementation bindings to implement a new subclass of WPAbstract? The two primary differences are that the instance variables introduced by the new subclass can include C++ objects, and the method procedures used by the C++ programmer to implement the overridden and newly introduced methods for the new class can make use of local variables that are C++ objects.

Of course, C++ usage bindings for a SOM class should be a great improvement over the C usage bindings, since the C++ usage bindings can be based on inline method expansion instead of macros, resulting in the elimination of any macro "collision" problems of the C bindings. Also a C++ compiler could then type check SOM object usage.

Subclassable

With the Subclassable approach, a C++ programmer would use a C++ class representing the SOM class WPAbstract (provided by the Subclassable C++ bindings for WPAbstract) as a base class for declaring and defining (in C++ -- not OIDL) a new derived C++ class whose parent is the C++ class provided by the C++ usage bindings for WPAbstract. This new derived C++ class is not a SOM class. However, if it is desired to publish this new subclass as a SOM class (thereby making it available and useful to languages other than C++), then it is possible to do this -- using essentially the same technique as was used to create the Subclassable C++ bindings for WPAbstract.

The Subclassable bindings would be more complex and present additional execution-time tradeoffs. We have created prototype emitters to demonstrate that the process of generating these bindings can be automated, and we are currently evaluating tradeoffs.