A comparison of technologies revisited yet again
Los Angeles, California
This document was prepared as a counterbalance to an IBM document that attempted to position SOM as a viable alternative to COM by perpetuating some completely unfounded myths about both technologies. It is important to note that:
This document is not meant to act as a stand-alone comparison of SOM and COM, but rather as an antidote to a completely random WebPage!
Object enabling technology consisting of an simple yet elegant object model and a lightweight runtime support system sufficient for implementing language-independent objects on virtually any platform that supports dynamic linking. COM is a binary standard that imposes no additional runtime cost to objects created using traditional C++ compilers and can be hosted in any language that supports implementing and calling functions with C linkage though a pointer. COM solves the problems of multi-language access and fragile base classes allowing class libraries to be distributed and reused in binary form with release to release compatibility. One key benefit of COM's binary object model is its capability to transparently access in-process and out-of-process objects without express support from the object or client.
Ostensibly, a "language-neutral" binary object specification that is completely proprietary and does not adhere to the native representation of any pre-existing commercial language or compiler. Special purpose compilers are now available from a small number of vendors that support the model natively, but most mainstream compiler vendors have rejected SOM as their native binary standard. While SOM is capable of allowing traditional OO-style inheritance for in process objects only, it is incapable of using any technique besides composition if the "base class" resides in a different address space or host machine. In fact, SOM and DSOM are two different models and require different source-level implementations per model.
SOM requires you to work in two worlds: Object-oriented for in-process objects, Object-based for out-of-process/remote objects. Two models, two reuse paradigms. To reuse an object that exists in a different address space, you must use containment and forwarding, requiring explicit invocation chaining from "derived" to "base" at each level of inheritance.
COM is a way of life. Many concepts present in OO methodologies are present (polymorphism, interface inheritance, delegation/containment). The one concept that COM, DSOM and pure CORBA lack is implementation inheritance at the binary level. COM provides a technique called Aggregation that allows a "derived" class to "inherit" all of the interface implementations of the "base" class that scales to arbitrary levels of inheritance. COM forces the "derived" class to replace the members of the base at the interface level not the individual method level, helping the designer to ensure the semantic integrity the "base" class by forcing the "derived" class to replace all or none of a family of related methods. To allow the "upcall" effect of virtual functions in C++, COM also supports an event model that allows the "base" class to issues method calls that can be intercepted by any "derived" client.
Based on the parlance (e.g. Wegner, OOPSLA 87) popularized in the 1980's, object oriented programming presumes implementation inheritance. A correct characterization of the methodology is important because it typifies the programming paradigm that will be found in applications built using the methodology. COM requires programmers to adopt an new and somewhat unfamiliar programming model that refines the techniques used to express implementation and interface hierarchies and is designed from the ground up to support binary reuse and transparent distribution. SOM, on the other hand, performs non-trivial runtime processing to simulate the programming model familiar to circa 1984 programmers that are accustomed to deeply nested object-oriented designs. Of course, this simulation only applies to in-process objects, and is not available in Distributed SOM, which supports only primitive forwarding/containment.
Language-neutral, but somewhat C++ hostile unless proprietary compilers are used. Objects may be written in C or C++. According to IBM, Smalltalk and Cobol bindings are under development by additional vendors. Direct-to-SOM C++ products (currently only available from Metaware and IBM) map some C++ classes directly into SOM.
Language-neutral, but very C++ friendly. Objects may be written in C or C++. C++ users simply inherit from an interface. C users are a masochistic lot, and are responsible for constructing the function table explicitly. Users of Visual Basic, arguably the first Direct-to-COM programming environment, simply implement member functions and do not need to explicitly do anything to enable the "com-ness" of their objects. Objects may be written in any language that supports building arrays of function pointers. Writing objects in C is more involved because the function table must be constructed manually, however C++ classes simply derive from the interface classes that are to be supported. Interestingly, the C++ method of using a abstract base classes for building the function table works with all commercial C++ compilers commonly used under Windows - as all of these compilers can lay out the vtable structure the same way. No use of virtual inheritance is used (or needed).
SOM's object model was difficult to implement in any OOPL environment until IBM and one other vendor (Metaware) provided a special SOM-compliant compiler. SOM can be used as a common binary runtime engine for C++ compilers and other OOPLs, and in fact is for exactly two C++ compilers. The core requirement of COM, the vtable, has always been the native object representation for large numbers of C++ compilers, including most CFRONT-based compilers.
Objects statically typed via the class hierarchy. For static method invocations, the compiler checks that a class is of the appropriate type.
Interfaces are statically typed. For all interface method invocations, the compiler checks that the parameters are of the appropriate type. The interface is discovered at runtime, allowing the type system of an object to evolve over time. Type libraries can be used to advertise the type system of an object, allows clients to "predict" the outcome of interface discovery at compile-time.
Static typing permits the language compiler to prevent type mismatch errors from showing up at runtime. Lack of static typing introduces more runtime failure modes. COM objects do not require runtime operations to ascertain which interfaces are supported by an object, but they do require runtime operations to dynamically bind to each interface.
Provided by the DSOM framework, a CORBA-like extension that does not support inheritance and requires a different object implementation than SOM. As in pure CORBA, all object references are marshaled by value, forcing each method call to incur a client-server roundtrip. Optimized "smart-proxies" must be statically specified and linked for each object implementation, requiring explicit support for both client and object.
Dynamic Invocation interfaces went remote in September 1995 with the release of Remote Automation, which leverages much of the security and protocol independence of DCE RPC. Complete infrastructure services and OS integration will be provided in the Cairo release of Windows NT sometime in 1996 (beta). Most major CORBA vendors support OLE to one degree or another. Few CORBA vendors support the proprietary extensions to CORBA introduced by SOM. COM supports both the pure CORBA marshaling architecture, where objects are marshaled by reference using proxys and stubs, as well as marshaling through subcontract, where the object (not the interface) can specify it's own unique distributional characteristics transparently to the client.
Provided by OpenDoc, a compound document technology that relies on SOM, which only allows inprocess objects. OpenDoc is slated to be released in late 1995/early 1996. As there are few if any commercial containers or parts available for mainstream platforms, it is impossible to guess the long-term viability of this standard. Although OpenDoc parts can be hosted in OLE containers, the part is actually loaded into a separate OpenDoc proxy-process, eliminating the lightweight nature of OpenDoc. In contrast, inprocess OLE Document objects can be hosted directly by OLE Document containers.
Provided by OLE Documents which allow both in-process and out-of-process objects. OLE Documents are supported by a wide range of mainstream applications currently in use. OLE Document support is a logo requirement for most Windows 95 applications. As OLE is in widespread use, it evolves rapidly, and upcoming extensions will include irregularly shaped Documents, pagination, and cross-document text processing.
Handled via proprietary pre-methods that must be explicitly invoked in every method implementation.
Unless a Direct-to-SOM compiler is used, inheritance is not directly supported and must be emulated by SOM system calls, and only for the inprocess case.
Except for object instantiation, no COM code is involved in interface selection or function invocation. In this area COM is only a set of rules, all code involved in interface selection or function invocation falls out naturally from any C++ compiler. This is one of COM's greatest strengths. SOM, on the other hand, requires off-line method resolution (i.e., interface selection and function invocation) through a metaclass, via SOM libraries and system calls. SOM users may, however, optionally elect to participate in method resolution by overriding the somDispatch mechanism. COM users may optionally elect to participate in method resolution by overriding the IDispatch::Invoke mechanism.
Supports single, multiple and abstract (interface) inheritance. Complete encapsulation of base class from derived class. Subclass uses only the published interfaces of the base class. Versioning is handled automatically during class construction. SOM has several mechanisms such as somIsA, etc.that cannot be used to fully simulate COM Aggregation
Traditional OO inheritance is fully supported at the interface level. In lieu of implementation inheritance, COM offers aggregation to allow implementation hierarchies. The laws of IUnknown allow for a clean object composition architecture that while simple, is somewhat different than the circa 1985 approach to reuse most of the world is used to.
Aggregation is a technique that allows for direct access to the object implementation. As aggregation is simply a mechanism specified by COM, once the interface in question is discovered via QueryInterface, no system code is needed. On the other hand, SOM's implementation inheritance is achieved through special pre-methods that resolve object/method references at runtime. In addition, lack of support for inheritance in DSOM means implementors must cope with 2 different object models, one for inprocess objects, and a different one for out-of-process objects.
COM capabilities require user discipline and adherence to simple protocol conventions, both of which are easily addressed using class libraries or frameworks currently available. SOM mechanisms require infrastructure support from the runtime environment. Methods internally invoked within an implementation can interact derived COM classes through the use of connection points and events. Unlike SOM, COM member functions cannot be randomly overridden in derived classes without explicitly replacing the entire interface implementation using aggregation. Despite the overblown terminology, most SOM reuse mechanisms are expressly prohibited in DSOM, and require considerably more discipline to program correctly.
Automatic base/derived class version checking using major & minor numbers. Optional user-written versioning using major & minor numbers. Evolution of classes permits refactoring methods, additions to inheritance tree, changes in object size, additions to interfaces.
COM interfaces are immutable never versioned. New interfaces have completely unrelated names (guids). Changes in the interface inheritance tree are not allowed, nor are they needed, as a single object can implement as many interfaces as are needed. Object size is not visible nor is it relevant, as it is an implementation detail that would require a client/derived/base coupling that would require SOM-like gymnastics to negotiate. Additions may be made to interfaces through derivation. Old interfaces may be supported in new objects at the implementor's discretion .
There is a dramatic difference in philosophy between SOM and COM here. SOM requires the implementor to manage release order compatibility to allow objects to evolve over time without breaking existing client programs. In COM, interfaces are immutable and no management is required. Also, in SOM versioning is a requirement, while it is unnecessary in COM.
All object lifecycle support provided including object creation, object destruction, object factories.
All object lifecycle support provided including object creation, object destruction, object factories. Object lifetime control is inherent in the COM protocol, and is easily implemented in 5 lines of boilerplate code or is provided by support libraries and frameworks. Clients coded using smart pointers require no explicit coding.
COM is a "language-neutral" packaging technology for class libraries. It permits libraries of object classes written in various object-oriented or procedural languages to be distributed in binary form, either as part of an operating system, a vendor tools product, or an application. Client programs written to use COM-based class libraries are insulated from dependencies on unintentional details of the object's implementation, so that the supplier of the class library may produce subsequent releases with fixes or enhanced capabilities without fear of breaking the client programs. The COM model is based on a well-defined protocol that is easily expressed using commonly available frameworks. The type system of an object is fully discoverable at runtime.
Incorporation of standards assures that widespread user requirements are being addressed and that compatible APIs and products may appear across a broad range of industry platforms. COM is an well-documented standard that is easily hosted on any platform that supports dynamic linking. Virtually all CORBA vendors are explicitly committed to support the COM standard, while precious few vendors have announced support for IBM's SOM.
It is easy to overlook the simplicity and elegance of COM as merely providing support for language neutrality and release-to-release binary compatibility. But, in fact, COM embodies an advanced object model with some very important and desirable capabilities including:
SOM has comparatively impoverished relevance in the marketplace, but is the dominant object model of OS/2.