Next: 3 Using a Prototype
Up: Towards a formal composition
Previous: 1 Introduction
A component is a black box entity with a set of required and provided services. It is obvious that connections have to be established between required and provided services. This is where the glue part of the composition language comes into play. In our terms, the glue acts as a means of communication between the components: it is responsible for component instantiation, configuration, and for correct intercomponent data transmission. Glue can be seen as a kind of software bus where components are connected to.
It is important that an application developer should have the choice to specify the control flow of an application either by using a component with a predefined control flow or by using abstractions provided by the composition language itself. We will denote the former kind of application development as embedding, the latter as scripting.
When combining components written in two different languages, so-called paradigm clashes might occur. As a first example, we had the following memory problem when we embedded a C++ program into a Smalltalk application: the Smalltalk application tried to access an object (where it still had a reference to) which already had been destructed by the C++ program. This invalid memory access resulted in a complete crash of the application. An ad hoc solution to this problem is to define a specific glue layer between the two languages which handles shared memory accesses. The disadvantage of this solution is that this glue layer has to be rewritten for each new application using both C++ and Smalltalk.
Second, Delphi is a component-based development environment suitable for Windows and database applications. A major disadvantage of Delphi is that it does not support dynamic linking of components and, therefore, all components of an application have to be already known at compile time. This often results in huge monolithic applications where it is not possible to exchange components at run time.
In order to overcome these kinds of problems, we think that the essential concepts and mechanisms have to be extracted from existing component and glue models, formalized, generalized, and integrated into a general-purpose composition language. It is not yet precisely clear, what the essential concepts and abstractions of composition will be, but in section 1 we have already listed some of the features a composition language must support.
It is clear, however, that we cannot completely separate the glue model from the rest of the composition language; everything has to match each other. Especially the glue and the component model have to work hand in hand, since the glue acts as a kind of telecommunication switch between the components. It is, therefore, not easy to precisely separate the requirements for those two models.
We argue that both the component and glue model of a composition language must be open. The component model needs to be open in order to define new component types (possibly as a composition of other components). Since the glue model has to match the component model, this implies that the glue model also has to be open. But this is not enough. In order to allow a highly readable and compact specification of applications, an application developer should be able to define new abstractions and change the semantics of existing ones. Therefore, the complete language model needs to be open.
It is important for application developers that the component model a composition language offers provides a uniform view of components. It should not be necessary (or even possible) to know in which language a component has been implemented. The interface of a component must contain all the necessary information (e.g., services) in order to use it in a safe and predictable way. This requires that all components follow a specific interface standard. If we want to use components not following this interface standard, we have to map them into the component model. We consider this mapping as a part of the glue model, which is another reason why the glue model needs to be open.
The glue is responsible for correct intercomponent data transmission. If the data format provided by one component does not match the data format required by another component, the glue has to transform the first data format into the second. This has the consequence that i) the glue model must support a basic number of data formats and knows how to transform them into each other, ii) new data formats and transformations can be added to the glue model, and iii) a user must be allowed to plug in special components which will do the necessary transformation.
When building an application, software engineers usually do not think in terms of language constructs, but in a much higher level using architectural guidelines and design patterns. Unfortunately, present day languages only offer very limited support to explicitly represent higher level design elements in the application itself. An explicit representation of design elements will not only result in faster application development, but also ease maintenance and extension of existing applications.
One approach to explicitly represent the architecture of a system in source code is to adapt the concept of executable connectors [DR97] to components. Connectors are runtime entities which define a set of rules how connected objects react and interact during external message sending. They change the observable behaviour without modifying the objects themselves. Therefore, connectors can be seen as a kind of higher-level glue for synchronizing and composing objects. We think that connectors are one of the key abstractions for defining architectural glue for larger applications and that they are most easily integrated when the composition language supports so-called message interceptors [SL97].
If we summarize the requirements discussed above, we can say that a composition language needs abstractions for i) instantiating and configuring components, ii) the definition of control flow, and iii) the specification of component interfaces. We now argue that all these abstractions should be based on a rigorous semantic foundation and be defined using the same mathematical model. What we need is a composition-calculus, allowing us to precisely define all abstractions of the composition language.
The -calculus is a calculus where both communication and configuration are primitives [Mil89] and which has successfully been used to model features of object-oriented programming languages [Wal95]. Our experience shows that the -calculus is a promising formal foundation for modeling concurrent objects [LSN96] and for the definition of higher-level, reusable synchronization abstractions [SL97]. Other work has proven that the -calculus can be used to precisely specify the configuration and behaviour of concurrent programs and to deduce behavioural properties [RE94]. Although the -calculus is rather low-level, it allows for defining and experimenting with higher-level abstractions, which can be easily mapped to the underlying calculus. We believe that the -calculus is powerful enough to model all abstractions we need for a composition language (especially for glue and scripting), and it is, therefore, a natural step to define our language on top of a -calculus based formal foundation.
Markus Lumpe, Jean-Guy Schneider, Oscar Nierstrasz, and Franz Achermann