Saturday, June 17, 2006

The independence of component-oriented development

Component-oriented development (COD) and distributed computing are distinct but closely related abstractions. This note discusses the relationship of these notions, as well as the independence of COD in the sense presented here. A specialization of component-oriented development known as service-oriented architecture is also discussed.

Unlike other writings on the subject of component-oriented development, this note does not discuss the advantages of COD. Instead, we examine the characteristics of a medium for materializing component-oriented development.

A concept is independent when the linguistic construct capturing its semantics is not a syntactic sugar within a formalism. An example for making the point clearer would be the claim that Lisp can be used to implement all other programming languages. The claim is only interesting when interpreted to mean that, the notion of list along with operations on list are sufficient for automating all other computational primitives.

An engineer uses the entire syntactic constructs of a language in composing a program. It may be true that all the mechanisms for constructing types, such as class, could be defined using the list primitive. We may as well assume that all constructs of structured programming could be defined using only list operations. However, a program also needs input/output, which require mechanized computational primitives equivalent to the operations of read/write. Thus, in order to support input/output Lisp must admit new linguistic abstractions that are not definable via the notion of list and list operations.

Another example for illustrating the notion of independence is the type-constructor task of Z++ Programming Language. Task is syntactically, and for the most part semantically identical to class. However, when an instance of task is declared the instance is actually created in a new thread. An engineer does nothing relating to threads, such as synchronization, critical section etc. Thus, task hides the details of the computational primitive of threading.

The important point here is that, without a computational primitive for threading, the linguistic abstraction of task would not have been possible. On the other hand, once the operation of threading is mechanized, many linguistic abstractions, such as task become viable.

In COD we deal with the composition and interaction of components. The composition of components needs primitives relating to linkage and other phases of compilation. Interaction of components may involve the operation of loading a component, perhaps remotely. These primitives may be presented inconspicuously in a language. Nevertheless, there will have to be new independent linguistic constructs that hide the details of these operations.

Early implementations of COD appeared in the form of library modules, like ADA packages. Later, dynamic mechanisms evolved this concept into dynamic modules, such as DLL. These implementations used the terms “export” and “import” for composing programs from library modules. The COD abstraction evolved out of a variety of attempts, such as CORBA.

This brief observation clearly indicates that the notion of component-orientation is independent of other notions such as structured programming and object-orientation. An independent abstraction requires technological innovations for its implementation. In the case of COD, these innovations must cooperate among the compiler, linker and the infrastructure.

A true formalism for COD will have to drop the distinction between a program and a component. That is, one must be able to compose a larger component out of any number of components, each of which could also behave as a standalone program. This is in contrast to the division of programs into executables and DLLs.

In a COD language, exceptions and signals generated in a component must propagate to other components in the chain until trapped. Obviously, the compiler must be able to see the relationship among components making up the larger component, without having to recompile the constituents.

A distributed algorithm is made up of components, though not necessarily in the sense of COD. The inception of component-oriented development appears to have been in the form of what is generally known as off-the-shelf components. However, the ability to compose a new component out of components already built on possibly a heterogeneous set of nodes is far more general and useful. We may assume that the conception of COD inherently included distributed computing, but that it was presented in various contexts.

Let us now turn to Service-Oriented Architecture (SOA). It is not attractive at all to rewrite everything once a more general and sophisticated language comes along. On the other hand, supporting everything everyone has chosen to do is begging for chaos. Expressive languages like ADA and C++ are here to stay, and therefore must be supported elegantly.

We consider SOA as a specialization of component-oriented development where components are written in different languages. A serious problem to solve for this specialization is of course interoperability. Z++ Programming Language provides a simple solution for interoperability with ADA and C++ through dynamic linkage.

Z++ compiler takes a set of dynamic libraries, like C++ DLLs, and generates a corresponding dynamic library in the target language. One only needs to compile the generated library in the target language, such as C++. The generated library furnishes direct linkage between Z++ and the target language.

Z++ uses the class construct for composition of components, whether or not components are written in Z++. This allows the use of other abstractions, such as class invariants and method constraints in composing a component from others.