A Meta-Model for Composition Techniques in Object-Oriented Software Development Bedir Tekinerdogan Department of Computer Science University of Twente P.O. Box 217, 7500 AE Enschede, The Netherlands E-Mail:
[email protected]
1. Introduction It is clear that compositional behavior has different aspects and meanings in the object-oriented software development area. In general, composition is needed to assemble or compose existing components together to get more complex or more adjusted functionality. The main issue here is that components should be freely and modularly combined [22], that is, we should not need to modify the existing components if we combine it with another component. Composition can be done either by black-box reuse or white-box reuse [15]. In the black-box reuse approach no internal details of objects are visible and objects appear as black boxes. In the white-box reuse approach the internal details of the object are visible. However, even in the case of white-box reuse the existing components should stay intact. Finally composition can be applied either at compile-time or run-time. Compositions in the conventional OO model are restricted to inheritance, encapsulation and communication protocols [1]. However, these composition techniques still suffer from providing real composability and other modeling problems [3]. Inheritance is a composition technique which is defined at compile time and is actually based on white-box reuse, because we need some internal details of the superclass if we would like to extend the existing class. As such we say that inheritance breaks the encapsulation [24]. The lack of powerful composability techniques for inheritance can further provide the so-called inheritance anomalies as described in [6][20]. Hereby we are forced to rewrite the original class in order to extend the base class. An alternative to inheritance is delegation [19] which is a composition technique that is adopted at run-time and which is more based on blackbox reuse. Although encapsulation is considered to be important for providing modular software it may provide obstacles for reusability and extensibility as well, because also information which is needed for reuse is hidden. Several approaches to solve this problem have been proposed as well. Finally, communication protocols can have additional constraints which the conventional object model and composition techniques cannot adequately cope with, like for example distributed, realtime and synchronization constraints [4] [5] [7] . In order to solve the compositional modeling problems we can identify two research approaches. The first approach takes the object models and tries according to some specific problem to find solutions. Subsequently, the object model is then adjusted for these specific situations. We adopt the second approach as it is illustrated in figure 1 and in which a meta-model of the compositional behavior of the object model is build. The problems of the object model and the solutions will be derived from this meta-model and accordingly new and better object models will be exploited. It is thus our concern to make explicit the composability issues of the conventional object model and identify the weak and strong aspects of the different object models. That is, in order to identify the basic problems like in traditional engineering techniques we will model our domain, which is in fact the OO model itself. Modeling the object model or part of it have been done by many authors and for several reasons [16] [21] [23]. All these meta-models have mainly in common that they try to solve some specific problems of the OO model which cannot be adequately encountered with the conventional OO techniques. We will distantiate us from specific problems of the object model and just try to make explicit the compositional behavior of the object model such that we can reason about it and accordingly control it in a later phase. Our meta-model will thus be an abstraction of the composition decisions which are
1
normally not accessible for the software engineer, like for example the strategy for the method-lookup and inheritance.
Figure 1. The two composability research approaches According to the separation of concerns principle [13], we will separate two concerns in our metamodel: First, the components in the software and second the composer objects, called composers, which compose the components. Composers will make explicit the control behavior and the dependencies among the different components in the object model. Using this approach we will see that we can identify different composers which are normally hidden in the functionality of the compiler. Our meta-model will be the basis for our research to adaptable and composable models and methods. Using this generic meta-model we will express the OO models adopted by different OO languages like Smalltalk [12], C++ [9][25], SELF [8] and SINA [2][17] and exploit the common powerful properties which support the composability and as such the adaptability of the software. We have to note that this is a preliminary work and as such the paper is really written as a position paper. The main goal of this position paper is to foster discussions and to obtain input for our further research in this area. The paper is further organized as follows. Section 2 will deal with the software components. Section 3 will describe the basic composers in the OO model. Section 4 will give the dependencies between components and composers. Finally, we will conclude with the conclusions and evaluations.
2. Software Components Software consists of components which are either primitives or composites. A composite component on its own may recursively include other primitive or composite components. Components will be composed by Composer which describes a specific composition protocol. We will use the Composite Design Pattern [11] for the structure of our compositions. Figure 2 illustrates the object model for the composers and the component.
Figure 2. The composite structure of software components Note that in contrary to the Composite Design pattern the composition semantic here has been left open and depends only on the kind of composite component. So the composition relation between a composite and other component can describe other relations than part-of as well. For the Composer it is not important whether the component is a primitive or a composition of components. It will treat all components in the composite structure uniformly. A Composer will use the Component’s class interface to interact with the components in the CompositionComponent. If the recipient is a SoftwarePrimitive, then the request will be handled directly. If the recipient is a CompositionComponent, then it will usually forward requests to its child primitives.
3. Composers The components are build by the composer. The primitive components together with the composers form the primitive entities in our meta-model. All compositional behavior in the object model will be made explicit in the composers. Since each language adopts slightly different object models we will
2
have different composers. Figure 3 gives a framework for the different abstract composers. These composers can be further tailored to the needs and requirements of the specific object models.
Figure 3. Composer hierarchy The UniversalComposer provides the abstract interface for the specific Composers. The underlying composers represent the basic composition functionalities for the composition of specific kind of components. Note that we did not make a distinction between compile-time and run-time composers. Whether the composer will be invoked at compile-time or run-time will be implicit in the semantics of the composer. The composers further differ in three ways. First, each composer will compose only specific components. For example ObjectComposer will only compose objects whereas MessageComposer composes Messages. Second, each composer will only accept specific kind of components. Third, each composer will have its own strategy on how to compose the accepted components. Composers will be classified using these three criteria. The next sections handle the different composers in more detail. ObjectComposer An ObjectComposer as illustrated in figure 4 composes an object from a set of slots [8]. A slot is a name-vale pair; slots may contain references to other components. Furthermore an ObjectComposer will assign an object id to the generated object. An id of a component in general, will be needed to uniquely identify the components.
Figure 4. The ObjectComposer MessageComposer A MessageComposer creates and manipulates Message components. The input of the MessageComposer consists of a set of entities which represent the selector name, the receiver name and the argument names. These entities will then be mapped to a Message component. This Message component has no context yet. Figure 5 illustrates the model for the MessageComposer.
Figure 5. MessageComposer
3
MethodComposer Figure 6 illustrates the composition of a Method component. The Method Composer will accept a set of messages composed by the MessageComposer, and will compose this in a Method component. Besides of the messages the MethodComposer will accept the control entities which include control statements and for example the return message. The messages will thus be put in the context of a Method component. In general Method components belong to classes. However, if we separate these from classes we can model the propagation patterns model [18]. Each method generated by a propagation pattern model may generate method components which is associated with many classes.
Figure 6. MethodComposer ClassComposer The ClassComposer will accept a set of instance variables and methods and compose this in a class component which will have also a class id. If we are concerning object-based languages which do not include the class concept then we may not need this kind of composer.
Figure 7. ClassComposer InheritanceComposer The InheritanceComposer as illustrated in figure 8 composes an InheritanceComposite by accepting Class components. Again the InheritanceComposer will put an inheritance id in the InheritanceComposite component. Furthermore the kind of composition strategy will determine what kind of inheritance the object model will use, single-inheritance, multiple inheritance, static inheritance, dynamic inheritance etc. From this example it is clear that we may then have many dedicated subclasses of the abstract ClassComposer of figure 3.
Figure 8. InheritanceComposer InstantiationComposer The InstanceComposer of figure 9 composes instances of a specific class in an InstanceOfComposite. This means that the InstantiationComposer will assign a class id to the InstanceOfComposite. This
4
composer will be typically adopted at run-time. In class-less language object models we will not need this Composer as well.
Figure 9. InstanceComposer
MessageCallComposer The MessageCallComposer as illustrated in figure 10, is another run-time composer which composes an object with a message. The method lookup strategy will be made explicit in this composer.
Figure 10. MessageCall Composer
4. Composer and Component dependency We have seen before that each composer can only create specific components. However, for different OO models we will need different composers. This means that composers differ in the kind of model adopted. If we adopt a Smalltalk OO model we will have a different ClassComposer than the model adopted by for example C++. However, we will still have the same component of a class. As such composer can be considered as a strategy for the components. Each component may then be associated with several composers. For this purpose we will use the Strategy Design Pattern [11] as illustrated in figure 11.
Figure 11. The composer as a strategy The collaborations in this design pattern are as follows: • The component here forms the context of the Strategy which is the Composer. The component will pass all data required by the algorithm to the composer when the composition algorithm is called. Alternatively, the component can pass itself as an argument to the Composer operations. • A components forwards requests from its clients to its Composer. Clients usually create and pass a ConcreteComposer object to the component. After that clients will interact with the component exclusively. For our model we will provide a family of ConcreteComposer classes for a client to choose from. As an example figure 12 illustrates the event trace diagram [14] for the composition of a Class Component. First the MethodComposer will accept all the necessary components for the method and then update the Method. Subsequently this Method component can be used to compose a class component.
5
Figure 12. An event trace diagram for the composition of a class
Conclusion & Evaluations In order to reason about composability we have made an attempt to provide a meta-model for the composability aspects of the different OO models. Although some things have to be worked out yet we think that exposing the composability behavior of the OO model using the initial meta-model presented can provide us useful input for our further research activities in composability. Our position statements for the workshop can be summarized in the following statement. Using a meta-model for the compositional behavior will provide us more insight in the deficiencies and the strengths of the object-model.
References [1].
M. Aksit. Separation and Composition of Concerns. Position paper for the ECOOP ‘96 adaptabilty in OO software development workshop, 1996.
[2].
M. Aksit. On the Design of the Object-Oriented Language Sina, Ph.D Thesis, University of Twente, 1989.
[3].
M. Aksit and L. Bergmans. Obstacles in Object-Oriented Software Development, Proc. of the OOPSLA'92 Conference, ACM SIGPLAN Notices, Vol. 27, No. 10, October 1992, pp. 341-358.
[4].
Aksit, J. Bosch, W. v.d. Sterren and L. Bergmans. Real-Time Specification Inheritance Anomalies and Real-Time Filters, Proc of the ECOOP '94 Conference, LNCS 821, Springer Verlag, July 1994, pp. 386-407.
[5].
C. Atkinson, S. Goldsack, A. Di Maio and R. Bayan. Object Oriented Concurrency and Distribution in DRAGOON, Journal of Object-Oriented Programming, March/April 1991, pp. 11-18.
[6].
L. Bergmans. Composing Concurrent Objects, Ph.D. thesis, University of Twente, The Netherlands, 1994.
[7].
J-P. Briot and A. Yonezawa. Inheritance and Synchronization in Concurrent OOP, Proc of the ECOOP'87 Conference, Springer-Verlag, 1987, pp. 32-40.
[8].
Craig Chambers. The Design and Implementation of the SELF Compiler, an Optimizing Compiler for Object-Oriented Programming Languages. Ph.D. dissertation, Computer Science Departments, Stanford University, March 1992.
[9].
J. O. Coplien. Advanced C++ Programming Styles and Idioms. Addison-Wesley, Reading, MA, 1992.
6
[10]. D. Decouchant, P. Le Dot, M. Riveill, C. Roisin and X. Rousset de Pina. A Synchronization Mechanism for an Object-Oriented Distributed System, Proc. of the 11th IEEE Conference on Distributed Computing, May 1991 [11]. E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design Patterns: Elements of Reusable ObjectOriented Software. Addison-Wesley, 1995. [12]. A. J. Goldberg & D. Robson. Smalltalk-80: The Language and its Implementation. AddisonWesley, Reading, MA, 1983. [13]. W. Hursch and C. Lopes. Separation of Concerns, Northeastern University, February, 1995. [14]. I. Jacobson et. al. Object-Oriented Software Engineering- A Use Case Driven Approach. [15]. R. E. Johnson and B. Foote. Designing reusable classes. Journal of Object-Oriented Programming, 1(2):22-35, June/July 1988. [16]. G. Kiczales, J. des Rivières & D.G. Bobrow. The Art of Metaobject Protocol. MIT Press, 1991. [17]. P. Koopmans. Sina/st User’s Guide and Reference Manual. Dept. of Computer Science, University of Twente. [18]. K. Lieberherr. Adaptive Object-Oriented Software: The Demeter method with Propagation Patterns, PWS Publishing Company, 1995. [19]. H. Lieberman. Using prototypical objects to implement shared behavior in object-oriented systems. In Proceedings of OOPSLA ‘86, pp. 214-223, Portland, OR, 1986. [20]. S. Matsuoka & A. Yonezawa, Inheritance Anomaly in Object-Oriented Concurrent Programming Languages, in Research Directions in Concurrent Object-Oriented Programming, (eds.) G. Agha, P. Wegner & A. Yonezawa, MIT Press, April 1993, pp. 107150 [21]. J. McAffer. Meta-level Programming in Coda, Proc. of the ECOOP ‘95 Conference, LNCS 952, Springer-Verlag, 1995, pp. 190-214. [22]. B. Meyer. Object-Oriented Software Construction, Prentice Hall, 1988. [23]. M. Mezini. Dynamic Metaclass Construction for an Explicit Specialization Interface, Dept. of Elect.Engineering and Comp. Science, University of Siegen, 1996. [24]. P. Mullet, J. Malenfant and P. Cointe, Towards a Methodlogy for Explicit Composition of MetaObjects, OOPSLA 95 Conference Proceedings, ACM Sigplan Notices, Vol. 30, No. 10, October 1995, pp. 316-330. [25]. A. Snyder. Encapsulation and inheritance in object-oriented languages. In Proceedings of OOPSLA ‘86, pp. 38-45, Portland, OR, November 1986. ACM Press. [26]. B. Stroustrup. The C++ Programming Language. Addison-Wesley, Reading, MA, 1991.
7