GENERALIZATION AND INSTANTIATION FOR COMPONENT REUSE

0 downloads 0 Views 283KB Size Report
Apr 13, 2006 - generalization that creates generic components by parameterizing specific ones. ... The earlier reuse is applied in the software process, the more gain can be .... following we give the definitions of signature and specification ...
April 13, 2006 9:47 WSPC/117-ijseke

00276

International Journal of Software Engineering and Knowledge Engineering Vol. 16, No. 2 (2006) 175–200 c World Scientific Publishing Company

GENERALIZATION AND INSTANTIATION FOR COMPONENT REUSE

SAMIRA SADAOUI∗ and PENGZHOU YIN Department of Computer Science, University of Regina, Regina, SK S4S 0A2, Canada ∗ [email protected] Submitted 10 March 2004 Revised 14 April 2005 Accepted 7 August 2005 There is an increasing need for high-quality software components. Reusable components and formal specifications are two complementary and promising approaches to achieve this goal. One method for enhancing the reusability of existing components is generalization that creates generic components by parameterizing specific ones. Generalization and instantiation are two methods related respectively to the development for reuse and development with reuse. Generalization, that is the abstraction of existing components, identifies commonalities across a class of entities, while instantiation customizes the general properties under different circumstances. In this paper, we present several generalization and instantiation algorithms for algebraic specifications. A major difficulty during the generalization process is determining the appropriate level of generality. Highly specific components have little chance of being reused. Meanwhile, if a component is too general, its reuse might also be hard. Therefore, we introduce a novel method based on the categorized constructors to control the level of abstraction in generic components with the goal of producing effective reusable components. Through a medium-scale example, the generalization and instantiation operations are illustrated in detail. Keywords: Algebraic specifications; CASL; generalization; instantiation; parameterization; reusable components.

1. Introduction Reuse, a major goal of modern software engineering, is considered the key to improving the quality and productivity of software [17]. To achieve these benefits, it is necessary to build software from components that are as reusable as possible. Software reuse can simply be defined as the “systematic application of existing software artifacts during the process of building new software systems; an artifact is a piece of formalized knowledge that can contribute to the software engineering process” [10]. The reusable artifacts can take many forms: requirements, specifications, architectures, transformation rules, code, etc. Existing research on software 175

April 13, 2006 9:47 WSPC/117-ijseke

176

00276

S. Sadaoui & P. Yin

reuse focuses on black-box components, domain-specific architectures, library systems and program generators [17]. Despite its attractiveness, software reuse is still not effective as it might be [12, 21]. Its success relies on the quality of reusable components, efficient reuse processes and early reusability in the software development. The earlier reuse is applied in the software process, the more gain can be achieved [6, 10, 12]. One way of delivering higher quality components is to apply formal techniques into their development [5, 11]. In fact, formal specifications describe the essential syntactic and semantic information of the possible implementations of a component, thereby providing a basis for software reuse. They offer several features that are useful for reuse including theoretical concepts and pragmatic issues, such as a high level of abstraction, modularity, superior descriptive power, code generation, provable semantics, prototyping capabilities, and supporting tools [23]. One method for supporting reuse is component generalization that can greatly enhance the reusability of existing components [19, 22, 26]. Generalization creates correct reusable components from already developed and tested ones as opposed to the standard approach that directly creates components for future reuse. The cost of developing generic components can be amortized by repeated use of these components (by instantiation) and by reducing the risk of introducing errors in the instantiated components. Generic programming is a method of making a program more reusable by making it more general using the parameterization mechanism [2, 13, 26]. Parameterization (or genericity) is important for software reuse and maintenance [3]. All programming languages support genericity at the implementation level while formal specification languages fulfill it formally. For instance, algebraic specification languages support constrained genericity, making it suitable for creating reusable components on the one hand, and correct instantiated components on the other hand. On the other side, model-based specification languages, such as B [25] and Z [14], lack the mechanism of parameterization and have limited restrictions on parameters [6, 20]. In this paper, we introduce several generalization and instantiation algorithms and propose a new method to control the abstraction level in generic components. The specification components are described here in CASL (Common Algebraic Specification Language) [4, 7]. Several algebraic specification languages have been defined and implemented in the past decade. Most of them share obvious similarities but each of them has its own features. Therefore, it is difficult for disseminating algebraic specification techniques in education as well as in industry [20]. As a result, CoFI (Common Framework Initiative) has developed CASL and two supporting tools CATS [8] and Hets [9]. We use these tools to compile and prove the correctness of our generic and specific vending machines. We note that our generalization algorithms are defined independently from any algebraic specification language and consequently can be applied to most of them. In our work, we also address the problem of over-generalization by giving some measures to prevent creating overly general specifications. Over-generalization could be a serious problem when building reusable libraries because it may be difficult to understand how

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

177

to use the general component [26]. Generalization, a complex operation, has not been studied enough. In [26], generalization is used to translate C functions into C++ function templates. This code generalization approach is useful in converting procedural code into an object-oriented one. In [20, 19], the authors have studied how to generalize the properties to be preserved in the generic component and also how to generalize their rewriting proofs. The rest of the paper is organized as follows. In Sec. 2, the necessary background is presented. Section 3 studies component generalization in detail and introduces three algorithms: syntactic generalization creates the most generic component, semantic generalization generates a generic component with constraints, and formal parameter generalization loses some constraints in the generic component. Section 4 covers three instantiation algorithms: basic instantiation replaces all the formal parameters, partial instantiation actualizes a subset of formal parameters, and general instantiation uses a generic component as the actual data type. In Sec. 5, a medium-scale example is given to illustrate the potential of the generalization and instantiation algorithms. In this example, we show how to generalize a highly structured specification and how to preserve the original hierarchy in the generic specification. In Sec. 6, we provide a comparison with work related to component generalization. Conclusion remarks and future directions are presented in Sec. 7. 2. Background To facilitate its reuse, we organize a specification component in two parts: (i) an auxiliary part including the auxiliary data types which might be defined in an existing library, and (ii) a local part including the sort of interest, its local operations and equations. A formal component COM is defined as a 3-tuple: COM = hAuxiS, LocalOpn, LocalEqni where COM is the unique name of the data type, AuxiS is the set of auxiliary data types, LocalOpn the set of local operations, LocalEqn the set of local equations. A parameterized specification component contains a generic structure and formal parameters that allow it to be systematically adapted into a possibly infinite set of specific components. For instance, in the “sorted queue of item”, the first-infirst-out strategy and the sorting algorithm are specified in the “queue” while the comparison between the elements in the queue is specified in “item” [16]: if the item is a number, a numerical interpretation is applied; if it is a string, a lexicographic interpretation is applied; if it is a user-defined data type, a user-defined interpretation is applied. The definitions of the generic structure and formal parameters are separated as shown in Fig. 1. Following this rule not only makes the specification clear but also makes formal parameters reusable. This is especially true when conducting generalization: after identifying the necessary constraints, we may first search the library of formal parameters before creating new ones. In our work, generalizing a data type consists of replacing some of its auxiliary types by more general types or formal parameters [22, 24]. The notion of general corresponds to

April 13, 2006 9:47 WSPC/117-ijseke

178

00276

S. Sadaoui & P. Yin

from Basic/SimpleDatatypes get Boolean spec ELEMENT = sort element op error: element; end spec STACK [ELEMENT] = type stack ::= nil | push(element; stack) vars s: stack; e: element op pop: stack -> stack . pop(nil) = nil . pop(push(e,s)) = s op top:stack -> element . top(nil) = error . top(push(e,s)) = e pred isEmpty: stack . isEmpty(nil) . not(isEmpty(push(e,s))) end Fig. 1.

(*predefined auxliary type*) (*formal parameter*) (*formal operation*) (*generic stack with one parameter*) (*stack with two constructors*) (*an operation*) (*an equation*)

(*a predicate*)

Generic component STACK in CASL.

the existence of a morphism between the formal parameters and the substituted auxiliary types. In algebraic specifications, the result of an operation can be used as an input argument of another operation. This mechanism is defined as the notion of term. A ground term is a term without variables. The semantics in an algebra is used to prove whether two terms are equal or not: A ` t1 = t2 means that from the semantics of the algebra A, two terms t1 and t2 are proved to be equal. In the following we give the definitions of signature and specification morphisms used in the generalization and instantiation algorithms. We note that Si denotes the set of sorts and OPi the set of operations. Definition 1 (Signature Morphism). Given two signatures Sig1 = (S1 , OP1 ) and Sig2 = (S2 , OP2 ), a signature morphism defined as g : Sig1 −→ Sig2 is a pair of applications g = (gs , gop ), where gS : S1 → S2 and gOP : OP1 → OP2 such that for each operation op ∈ OP1 : s1 , s2 , . . . , sk → s k ≥ 0, ∃ op2 ∈ OP2 /gOP (op : s1 , s2 , . . . , sk → s) = (op2 : gS (s1 ), gS (s2 ), . . . , gS (sk ) → gS (s)). Definition 2 (Specification Morphism). Specification morphism is a signature morphism such that the translated equations from the source algebra A1 are equations in the target algebra A2 . A specification morphism m is defined as m : A1 → A2 , such that ∀ t1 , t2 ∈ A1 , A1 ` t1 = t2 ⇒ A2 ` m(t1 ) = m(t2 ). 3. Component Generalization If we regard a specific component as a board, the generalization operation is to make holes on the board to promote its reusability under different environments [16]. The board is the generic structure while the holes themselves are the formal parameters. When digging holes, we might choose to make holes suitable for certain fillers. This

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse Table 1.

Abstraction Source component Set of constraints in formal parameter

179

Generalization types.

Syntactic generalization

Semantic generalization

Formal parameter generalization

high fixed/parameterized empty

low fixed/parameterized not empty

medium parameterized loosed

consists of defining the properties of holes, which are kept in the equations of formal parameters. Formally, we regard the process of making holes without properties as syntactic generalization, with properties as semantic generalization, and the process of altering the properties of holes as formal parameter generalization. We also note that the fixed/parameterized components refer to the boards without/with holes. The three types of generalization are defined below and compared in Table 1: • Syntactic generalization does not preserve the properties of the formal parameter (unconstrained genericity) [24]. After syntactic generalization, the equation part of the formal parameter is empty (as shown in the parameter ELEMENT of Fig. 1). • Semantic generalization preserves the constraints of the formal parameter (constrained genericity) [24]. After semantic generalization, the equation part of the formal parameter cannot be empty. In programming languages, genericity with constraints is not supported. • Formal parameter generalization loses some of the semantics of the formal parameter. Its source component is already a parameterized component. Generalizing a data type consists of replacing some of its auxiliary types by formal parameters. First, we have to decide which auxiliary sorts and which local operations are appropriate for a good generalization [22, 24]. The goal here is to avoid over-generalization which creates general components that are hard to understand and reuse. Our generalization is conducted in an incremental way, which means that we generalize only one auxiliary data type each time. Below we give the general definition of the generalization operation where COM and COM ] denote respectively the specific component and the general adaptable one, and sorts a function which returns all the sorts of a specification. Definition 3 (Generalization Operation). Generalization, a transformation operation, is defined as a specification morphism g : COM ] → COM where • COM ] can be used in more contexts than COM, i.e. COM ] has more formal parameters than COM or the semantics of the formal parameters in COM ] is loosened further. • g the signature morphism is defined as: — g : sorts(COM ] ) → sorts(COM ) — g : LocalOpn] → LocalOpn — g : LocalEqn] → LocalEqn

April 13, 2006 9:47 WSPC/117-ijseke

180

00276

S. Sadaoui & P. Yin

• there must exist an instantiation of COM ] that is isomorphic to COM. To make the introduction of the generalization algorithms easier, we give the following definitions: • Source auxiliary data type, AuxDT, is present in the profile of COM’s constructors but cannot be the sort of interest. • Source operations, LOpn ⊆ LocalOpn, is the subset of non-constructors in COM containing AuxDT in their profiles. However, LOpn includes only the operations where AuxDT is referred to as the internal element of the structure COM. This restriction prevent over-generalization of COM. As an example, in the operation “get : list, position → natural”, the range natural is referred to as the element of the list while in the operation “length : list → natural”, natural is only used as a counter. The generalization of get is worthy but the one of length is useless. • Source equations, LEqn ⊆ LocalEqn, is the set of corresponding equations of LOpn. • sorti, sorts, nconsts, eqns are functions which return respectively the sort of interest, the set of all sorts, the set of non-constructors and the set of equations for a given data type, and card returns the cardinality of a set. • Source auxiliary operations, OpnAuxDT ⊆ nconsts(AuxDT), is the set of operations defined in AuxDT and used by LEqn. • Formal parameter, FormalP, is a data type specifying the formal sort belonging to the profile of COM ] ’s constructors. 3.1. Syntactic generalization Sometimes syntactic generalization is too strong because we lose all semantics of the formal parameter. However, it serves as a starting point for semantic generalization. One problem with generalization is how to preserve the “meaning” of the operations in source components, i.e. how to control the level of abstraction so that we can keep the behaviors of components unchanged. Highly specific components have little chance of being reused. Meanwhile, if a component is too general, its reuse might be also hard. The aim of doing the meaning preserving generalization is to narrow down the generality of generic components. There are two main categories of operations in algebraic specifications: constructors and non-constructors. Their meaning are also presented in two different ways: • The meaning of constructors is the pattern of their profiles. For example, the profile of the constructor succ in NATURAL is: natural → natural, i.e. from a given number we can get the next one. The data type created by such kind of constructor is linear order because its ground terms are sequential starting from the first element. • The meaning of non-constructors are defined by their relationships with the constructor. For example, the same operation “+” has different forms of definition along with different formats of constructors.

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse Table 2.

181

Operations with the same meaning.

Meaning

Data type

Adding

Linear order Container set Container list

Removing

Linear order Container set Container queue Container stack Container table

Symbol of operation + ∪ merge — — dequeue pop remove

The symbols of operations also reflect their meaning. For instance, “+” in NATURAL means adding variables, so does the operation “∪” in data type SET.

However “—” means separating one from another. In table 2, examples of typical operations with the same meaning are listed. The algorithm of syntactic generalization is syntax-directed conversion: an auxiliary sort is replaced by a formal parameter whose definition is added in the resulting specification. To ensure the proper input, some pre-conditions are defined. After generalization, several requirements defined as post-conditions are met by COM ] to ensure its correctness. Profile: COM ] = generalize COM through AuxDT by F ormalP where • COM is the component to be generalized. • AuxDT is the name of the auxiliary data type to be abstracted. • F ormalP is the name of the formal parameter replacing AuxDT . • COM ] is the resulting generic component.

Pre-conditions: • COM must be specified in a many-sorted algebra, a single-sorted algebra cannot be a candidate for generalization. • AuxDT cannot be a formal parameter. • AuxDT must belong to COM’s constructors.

Algorithm: 1. Choose LOpn from nconsts(COM). 2. Create OpnAuxDT based on LEqn. 3. Create the signature of FormalP based on OpnAuxDT by mapping FormalP to AuxDT. 4. Combine FormalP with AuxiS together as AuxiS ] . 5. Inherit all constants in COM as the constants in COM ] and rename sorti(COM) by sorti(COM ] ). 6. Replace AuxDT in COM’s constructors with FormalP as constructors in COM ] . 7. Rename LOpn as operations in COM ] by replacing AuxDT with FormalP and sorti(COM) by sorti(COM ] ).

April 13, 2006 9:47 WSPC/117-ijseke

182

00276

S. Sadaoui & P. Yin

8. Check whether the operations in COM ] need AuxDT; if not remove it from AuxiS ] else keep it. 9. Rename AuxDT and OpnAuxDT in LEqn as COM’s equations.

Post-conditions: • eqns(F ormalP ) = φ. • There should exist a specification morphism g : COM ] → COM .

3.2. Semantic generalization The semantic generalization is concerned with the specification of the equations of the formal parameter. In [22], the properties of the formal parameter are defined from the abstracted auxiliary data type. For instance, when conducting semantic generalization on operation “+ : natural, natural → natural”, general properties of “+” are summarized, such as the commutativity, monoid structure, total or partial order, etc. These properties are specified in the formal parameter as the semantics of the generalized “+”. There are two problems with such kind of method. First, how to get all the properties of the auxiliary operations. For typical operations we can do the summary or borrow the rules from mathematics. However, for unusual and user-defined operations, how can we summarize their properties thoroughly? Second, if the properties are not covered completely, the meaning of the generalized operations will be twisted during the instantiation. In this section, we propose a new method to specify the semantics of formal parameters. Rather than identifying general properties, we choose to define the semantics of the formal parameter using categorized constructors because ground terms and all equations of data types are based on them. In order to create a uniform constructor which can be customized to any specific one, we summarize the constructors of typical data types as shown in Table 3. Table 3.

Typical constructors.

Constructor Profile

Sort of interest

Structure

succ : d → d add : d, l → l make : l, d, l → l create : l, d, m → m gen : l, d, m → n con : l → m

d l l m n m

linear order container tree table recorder converter

Example natural list, stack, set binary tree table recorder converter

By studying Table 3, we summarize the profile of constructors as below: n2 ni 1 con : dn 1 , d2 , . . . , di → d/d ∈ {d1 , d2 , . . . , di , di+1 } and ni , i ∈ N where

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

183

— con is the constructor’s name, dn1 1 , dn2 2 , . . . , dni i are its domain sorts and d its range sort. — i is the index of a sort meaning that there are i distinct sorts. — ni represents the occurrence of a sort. For instance, dni i denotes the sort di occurring ni times in the domain. We call the above formula the uniform constructor because it can be customized to any format by setting different values for ni , i and d. For instance, when i = 1, n1 = 1 and d = d1 , the formula becomes con : d1 → d1 which is identical to the profile of NATURAL’s constructor (succ : natural → natural). When i = 2, n1 = n2 = 1 and d = d2 , the formula becomes con : d1 , d2 → d2 which is the same as the constructor of SET (add : element, set → set). From the uniform constructor, we might create different constructors. In the following, we summarize the structures and create categories [24]: • Linear Order. If both the domain and range have only one identical sort, we call such kind of constructors linear order. The uniform constructor becomes con : d1 → d1 where i = 1, n1 = 1 and d = d1 . This kind of constructor creates ground terms from a starting value and ground terms have a sequence on their own. The sample data type for this category is NATURAL. Although its structure is straightforward, there are lots of operations defined in this type. • Converter. If the range sort is not included in the domain sorts, such kind of constructors is called converter since a new sort is created and all domain sorts are converted into it. A converter has two subtypes: — Simple-converter when the domain has only one sort. For example, “con: natural → char” changes a natural number to a character. — Record when the domain has more than one sort and the new sort combines several sorts. For example, we construct a student record by the student’s name, ID, age and major as con : id, name, major, age → student. • Container. If the domain has more than one sort and the range sort belongs to the domain, we call such constructor container. The range sort combines all domain sorts and contains them. Container has four subtypes: — Sequenceless-container when the elements in the container have no sequence. For example, the set is a sequenceless container whose elements have no order. — Sequence-container when the elements in the container have a sequence. For example, the elements in the queue and stack are placed according to their sequence. The operations defined on such data types are also position-related. For example operation “pop” in stack removes the outermost element. — Tree and subcontainer if the set of domain sorts has more than one element identical with the range. Because when constructing data types in this category, we have several different branches to add elements. For example, we might have several positions to add leaves in a binary tree.

April 13, 2006 9:47 WSPC/117-ijseke

184

00276

S. Sadaoui & P. Yin Table 4. Number of element

rs

Categories of constructors. Structure

Example

card(DS) = 1

rs ∈ DS

linear order

succ : natural → natural

card(DS) = 1 card(DS) > 1

rs ∈ / DS

converter

con : natural → char con : id, name, major → record

card(DS) > 1

rs ∈ DS

container

con : set, element → set con : queue, element → queue con : stack, element → stack con : tree, tree, element → tree con : table, key, element → table

— Table when the domain sorts have one key sort, and the key acts as the index to the resting sorts. The constructor categories are summarized in Table 4 where “DS” is the set of domain sorts and “rs” is the range sort. Regarding the categories, we do not confine ourselves to the simple form of the formula. The constructors which fall into the same category might have different profiles. For example, con: list, data → list, con: list, data1 , data2 → list and con: list, data1 , data2 , . . . , datan → list are all regarded as containers, because they have the typical structure of container: their range sort belongs to the domain set which has more than one element. We can regard the semantic generalization as adding constructors and equations to the formal parameter whose signature has been generated during syntactic generalization. During semantic generalization, we distinguish constructors as linear order, converter or container. However, when writing equations for the formal parameter, we just specify them using the basic form of each category. For example, when specifying equations for record, we use just its basic form as con : l, m → k, where its category is commented as a reference for the instantiation. The profile, pre-conditions, algorithm and post-conditions of semantic generalization are presented below. Profile: COM ] = generalize COM through AuxDT by FormalP on TYPE where • TYPE indicates the constructor category added to FormalP.

Pre-conditions: The pre-conditions of COM, F ormalP and AuxDT are identical with syntactic generalization. Semantic generalization requires the following extra condition: • TYPE ∈ {LINEARORDER, CONTAINER, CONVERTER}

Algorithm: The specific part of semantic generalization is adding formal equations to FormalP assuming that we already have the signature of FormalP from syntactic generalization. 1. if TYPE = LINEARORDER then — add linear order constructor to FormalP with the profile con : sorti (FormalP ) → sorti (F ormalP ). 2. else if TYPE = CONTAINER then — include ITEM as the auxiliary data type for FormalP. ITEM is first defined as: type ITEM endtype.

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

185

— add container constructor to FormalP with the profile con : item,sorti (FormalP ) → sorti (FormalP ). 3. else if TYPE = CONVERTER then — DATA and ITEM are introduced as the auxiliary data types for F ormalP . DATA and ITEM are first defined resp. as: type ITEM endtype and type DATA endtype — add converter constructor to FormalP with the profile con : data, item → sorti(F ormalP ). 4. Add operations to ITEM and DATA if necessary. 5. Specify the formal equations based on the added constructor. 6. If an operation has no meaning w.r.t the added constructor, leave its equations empty. 7. After specifying the formal equations in FormalP, the rest of the procedure is identical with syntactic generalization.

Post-conditions: • eqns(F ormalP ) 6= φ. • There should exist a specification morphism g : COM ] → COM .

3.3. Formal parameter generalization This kind of generalization makes the source component more general by losing the semantics of the formal parameters. After semantic generalization, the formal operations are defined only with categorized constructors and the set of formal equations for one operation is completely independent from the other operations. Therefore, each formal operation has a set of equations on its own. The formal parameter generalization, presented below, is conducted in an incremental way, i.e., we only remove the set of equations for a given formal operation. The steps of generalization algorithm are given below. Profile: COM ] = generalize COM through F ormalP with OpnAuxDT where • COM is the component to be generalized. • FormalP is the name of formal parameter in COM. • fop is the formal operation whose equations will be removed. • COM ] is the resulting generic component.

Pre-conditions: • COM must be a generic component and uses FormalP as its internal element. • OpnAuxDT ∈ nconts(FormalP).

Algorithm: 1. Choose OpnAuxDT from nconsts(FormalP). 2. If OpnAuxDT has no formal equations then quit. 3. Remove the whole set of formal equations for the chosen operation. 4. If all formal equations in FormalP have been removed, delete the constructor.

Post-conditions: There should exist a specification morphism g : COM ] → COM .

April 13, 2006 9:47 WSPC/117-ijseke

186

00276

S. Sadaoui & P. Yin

STACK of NATURAL ion

eralizat

ic Gen

Syntact

ant

ma

Se

STACK of ELEMENT

Sem

on

zati

rali

ene

G ntic

GSTACK1 of LINEAR ORDER Formal Parameter Generalization

c Gener

ene

rali

alizatio

n

zati

on

GSTACK2 of CONTAINER

Formal Parameter Generalization

GSTACK1 with some formal equations removed

Fig. 2.

Semanti

ic G

GSTACK3 of CONVERTER Formal Parameter Generalization

GSTACK2 with some formal equations removed

GSTACK3 with some formal equations removed

Generalization algorithms.

In Fig. 2, we illustrate how the generalization algorithms are powerful enough to include all possible data structures. From the same specific component STACK of NATURAL, four generic components can be created covering all possibilities: the component STACK of ELEMENT is shown in Fig. 1; the components GSTACK1, GSTACK2 and GSTACK3 are respectively defined with linear order, container and converter constructors. After semantic generalization, we can still conduct the formal parameter generalization and make generic components more general. 4. Component Instantiation Generalization is the abstraction of a specific component while the instantiation, the reverse operation, is the specialization of a generic component. If generalization is to dig holes on boards, then the instantiation is to find fillers for these holes. The instantiation mapping is also defined as a specification morphism from the general component to the specific one. The equations in the formal parameters are the constraints to select the actual data types. Indeed at the traditional instantiation, the actual data type must follow the syntax as well as the semantics of the formal parameter. This consists of generating proof obligations to verify that the actual type is a model of the formal parameter. The type and number of formal parameters affect the types of instantiation to be applied: • Basic instantiation actualizes all the formal parameters in the generic component. Instantiation with/without constraints refers to the actualization of formal parameters with/without equations. • General instantiation replaces a formal parameter with another generic specification component. Instantiation with/without constraints is also applied. • Partial instantiation occurs when there is more than one formal parameter in the source component, and we only instantiate some of them, not all of them. The resulting component is still a generic component. During the instantiation, we also want to preserve the meaning of the operations. The formal parameter and actual data types are linked by the categorized constructor. For example, if in the formal parameter, “+” is defined as “succ(m) + n = succ(m + n)” which reflects the relationship between “+” and

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

187

the constructor “succ”, so the image operation in the actual data type must have the same equations with its constructor which must be in the same category with “succ”. Conducting instantiation in this way has the following benefits: • Easy Selection. The constructor in the formal parameter becomes the first constraint for locating actual data types. The constructors of formal parameter and actual data types must be in the same category. • Easy Matching. The matching between formal and actual operations is based on their relationships with their own constructors. If both of them have the same equations with their own constructors, then the formal operation can be instantiated with that actual operation. • Easy Checking. The success of the instantiation depends on the correct selection and matching. Thanks to the categorized constructors, we do not need to generate proof obligations to verify if the actual data type satisfies the formal parameter. • Easy Organization. One of the problems in component reuse is how to organize the component library. One solution is to simply organize the reusable components by the constructor categories. For components in the same category, we can group them by the constructor arity. • Easy Development. The design of reusable components becomes generalization along with the categories. We can easily check whether a generic structure has been defined with all possible categorized constructors. The instantiation algorithm is given below. It is suited for all types of instantiation: basic, general and partial instantiation. Profile: COM ∗ = instantiate COM ] through FPList

by ADTList on sigMList

where • COM ] is a generic component to be instantiated. • F P List is the list of formal parameters to be instantiated. • ADT List is the list of actual data types replacing F P List. • sigM List is the signature morphism list from F P List to ADT List. • COM ∗ is the result of the instantiation operation.

Pre-conditions: • card(FPList) = card(ADTList). • The sequence of data types in FPList and ADTList are one-to-one correspondence, i.e. the first type in FPList is instantiated by the first type in ADTList and so on. • sigM List is not empty.

Algorithm: 1. For each data type in FPList do: — Check whether the constructors in formal parameter and actual data type are in the same category. — If constructor category does not match, return fail. — Check whether the operation pair in sigM List have the same equations with their own constructors. — If equations do not match, return fail.

April 13, 2006 9:47 WSPC/117-ijseke

188

00276

S. Sadaoui & P. Yin

2. Conduct the instantiation using the instantiation mechanism defined in CASL and based on sigM List.

Post-conditions: There should exist a specification morphism i : COM ] → COM ∗ .

Figure 3 illustrates our instantiation strategies. The result of syntactic generalization of Fig. 2, STACK of ELEMENT, can be actualized to any data types. For instance, if we use characters to actualize ELEMENT, it is a basic instantiation. In the instantiation with constraints, the actual data types must have the same categorized constructor with the generic component. For example, LIST, SET and STACK all have the container constructor, and therefore can be used to actualize GSTACK2 of Fig. 2. If we use the generic component LIST of ITEM to instantiate GSTACK2 (here we have a general instantiation), we get a generic stack: STACK of LIST of ITEM. STACK of ELEMENT Instantiation without constraints STACK of ANYDATATYPE

GSTACK1 of LINEAR ORDER Instantiation constraints

with

GSTACK2 of CONTAINER Instantiation constraints

with

Fig. 3.

Instantiation constraints

with

STACK of RECORDER

STACK of NATURAL STACK of LIST

GSTACK3 of CONVERTER

STACK of SET

STACK of STACK

Instantiation algorithms.

5. A Case Study The vending machine is chosen as a case study to demonstrate the usage of the generalization and instantiation algorithms. First the functionalities of a particular vending machine are introduced and then specified as algebraic abstract data type. After the limitations of the current model are identified, a more general vending machine is created which is then instantiated to produce a particular model based on new user requirements. The vending machine, an electronic device designed for automated selling, is chosen as a case study for the following reasons: • Comprehensibility. Vending machines are common in our daily life. Almost everybody has experienced using a vending machine to buy some drinks, and its functionalities are well understood. • Complexity. It is important to select an example which is large enough to illustrate the generalization and instantiation operations and at the same time, not very complex to be effectively presented in this paper. • Variability. The goal here is to create a generic model from the specific one and then adapt it to different scenarios. So the model being studied must allow enough variability. The concept of a vending machine is simple but there are various models of vending machines. Indeed, the generic model provides various services based on the basic functionalities.

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

189

The operations provided by a typical vending machine are the following: • Stocking things for selling. A vending machine is out of service if its products are all sold out. The typical products might be drinks, tickets, candies, chocolate bars, etc. • Interacting with buyers. A vending machine provides an interface which interacts with buyers and returns some results. The interface includes inserting coins, choosing an item, returning the chosen item and some change, etc. • Displaying information. Listing the necessary information for buyers and maintainers is also required for a friendly user interface. The messages for buyers are price, available items, etc. The information for the maintainer includes error messages, total money earned, etc. 5.1. A specific vending machine The existing vending machine, called VM, is divided into subsystems whose names are outlined in parentheses. VM has three types of drinks: milk, coffee and chocolate (NAME) and accepts quarter (QUARTER) as its smallest money item. Different drinks have different prices (MONEY). A collection of drinks (DRINK) is managed in a drink list (DRINKLIST). Data type MONEY. The price of each item is specified with type MONEY which uses QUARTER as its internal element. QUARTER has one constant oneQ denoting one quarter. The operations in MONEY are the following: “nullMoney” denotes the empty value; “add” constructs the value of money; “+” returns the total; “−” returns the difference; “grandeq” compares two amounts of money; “count” tells how many quarters are contained in a given money value; “eq” checks the equality of two money values. MONEY and QUARTER are defined in CASL as shown below. from Basic/SimpleDatatypes get Boolean from Basic/Numbers get Nat spec QUARTER = type Quarter ::= oneQ end spec MONEY = Boolean and Nat and QUARTER then vars m,n: Money; c: Quarter type Money ::= nullMoney | add(Money; Quarter) op __+__:Money * Money -> Money, comm . m+nullMoney = m . (add(m,c))+(n) = add((m+n),c) op __-__:Money * Money -> Money . m-nullMoney = m . m-m = nullMoney . grandeq(m,n) => (add(m,c))-(n) = add((m-n),c) op count: Money -> Nat . count(nullMoney) = 0 . count(add(m,c)) = succ(count(m)) pred __eq__:Money * Money, comm . (nullMoney)eq(nullMoney) . not((nullMoney)eq(add(m,c))) . (add(m,c))eq(add(n,c)) (m)eq(n)

April 13, 2006 9:47 WSPC/117-ijseke

190

00276

S. Sadaoui & P. Yin

pred grandeq:Money * Money . grandeq(m,m) . grandeq(add(m,c),nullMoney) . not(grandeq((nullMoney),(add(m,c)))) . grandeq((add(m,c)),(add(n,c))) grandeq(m,n) end

Data type NAME. The name of a drink is specified by type NAME whose operations are as follows: “eq” checks the equality of two names; “nullName” represents the empty value; three constants “milk”, “coffee” and “chocolate” denote the three types of drinks. NAME is defined as follows. spec NAME = Boolean then free type Name ::= nullName | Milk | Coffee| Chocolate pred __eq__:Name *Name, comm forall x,y: Name . (x) eq (x) . not((x) eq (y)) end

Data type DRINK. In VM, the selling item is specified in type DRINK which uses MONEY and NAME to represent its price and name. The operations in DRINK are the following: “nullDrink” represents the empty drink; “create” generates a drink by combining MONEY and NAME; “sum” calculates the total price of two drinks; “getMoney” returns the price of a given drink; “getName” returns the name of a given drink; “change” returns the extra quarters to the buyer; “canBuy” checks whether a given amount of money is greater than the price of the selected drink; “eq” checks the equality of the two drinks. DRINK is defined as follows. spec DRINK = MONEY and NAME and Boolean then vars m,m1,m2: Money; n,n1,n2: Name; d: Drink type Drink ::=nullDrink | create(Money; Name) op getMoney: Drink -> Money . getMoney(nullDrink) =nullMoney . getMoney(create(m,n)) = m op getName: Drink -> Name . getName(nullDrink) = nullName . getName(create(m,n)) = n op change: Drink * Money -> Money . grandeq(m2,m1) => change(create(m1,n),m2) = m2-m1 . not(grandeq(m2,m1)) => change(create(m1,n),m2) = nullMoney op sum: Drink, Drink -> Money, comm . sum(nullDrink,nullDrink) = nullMoney . sum(nullDrink,d) = d . sum((create(m1,n1)),(create(m2,n2))) = m1+m2 pred __eq__: Drink * Drink, comm . (nullDrink)eq(nullDrink) . not((nullDrink)eq(create(m,n))) . (create(m1,n1))eq(create(m2,n2)) ((m1)eq(m2))/\((n1)eq(n2)) pred canBuy: Drink * Money . canBuy(d,m2) grandeq(m2,getMoney(d)) end

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

191

Data type DRINKLIST. For the convenience of manipulating a bundle of drinks, we create the type DRINKLIST whose operations are defined in the following: “nullDrinkList” represents the empty drink list; “addDrink” inserts one drink into the drink list; “remove” deletes one drink from the drink list; “sum” returns the total price of drinks available in the drink list; “totalDrink” returns the number of drinks in the drink list; “getDrink” returns the first inserted drink in the drink list; “eq” checks the equality of two drink lists. DRINKLIST is defined below. spec DRINKLIST = DRINK and Nat and Boolean then vars d,d1,d2: Drink; b,b1,b2: DrinkList type DrinkList ::= nullDrinkList | addDrink(Drink; DrinkList) op getDrink: DrinkList -> Drink . getDrink(nullDrinkList) = nullDrink . getDrink(addDrink(d,b)) = d op sum: DrinkList -> Nat . sum(nullDrinkList) = 0 . sum(addDrink(d,b)) = count(getMoney(d))+ sum(b) op totalDrink: DrinkList -> Nat . totalDrink(nullDrinkList) = 0 . totalDrink(addDrink(d,b)) = succ(totalDrink(b)) pred __eq__: DrinkList * DrinkList, comm . (nullDrinkList)eq(nullDrinkList) . not((nullDrinkList)eq(addDrink(d,b))) . ((b1)eq(b2))/\((d1)eq(d2)) (addDrink(d2,b2))eq(addDrink(d1,b1)) op remove: Drink * DrinkList -> DrinkList . remove(d,nullDrinkList) = nullDrinkList . (d1)eq(d2) => remove(d1,addDrink(d2,b)) = b . not((d1)eq(d2)) => remove(d1,addDrink(d2,b)) = addDrink(d2,remove(d1,b)) end

Data type VM. VM uses DRINKLIST as its internal element. The operations in VM are as follows: “emptyVM” denotes the empty vending machine; “addDrinkList” adds one bundle of drinks into VM; “removeDrinkList” deletes one bundle of drinks from VM; “getDrinkList” returns a drink list from VM. spec VM = DRINKLIST then vars vm,vm1,vm2: VM; d,d1,d2: DrinkList type VM ::= emptyVM |addDrinkList(DrinkList; VM) op removeDrinkList: DrinkList * VM -> VM . removeDrinkList(d,emptyVM) = emptyVM . removeDrinkList(d,addDrinkList(d,vm)) = vm . not((d1)eq(d2)) => removeDrinkList(d1,addDrinkList(d2,vm))= addDrinkList(d2,removeDrinkList(d1,vm)) op getDrinkList:VM -> DrinkList . getDrinkList(emptyVM) = nullDrinkList . getDrinkList(addDrinkList(d,vm)) = d end

April 13, 2006 9:47 WSPC/117-ijseke

192

00276

S. Sadaoui & P. Yin

When examining the current model of VM, its limitations are obvious. In the following we discuss the main limitations and propose solutions to overcome them: • Only a limited type of items is supported. As mentioned before, the generic vending machine should be varied in services. For example, not only soft drinks can be sold but anything with a fixed price can be sold. In the current model only three types of drinks are available for buyers. So the data type denoting the items should be generalized to a formal parameter which may be actualized into different concrete products. • Only one type of currency is accepted. In VM, only one type of money is accepted, and the smallest money item is the quarter. The generic vending machine should accept different currencies. Therefore QUARTER must be generalized to a formal parameter, so that we can customize the money to any currencies we want. • Only one language is supported. It would be better if the generic vending machine can allow display of messages in different languages. In the current model only one displayed language is supported. By generalizing the data type NAME, we may internationalize the generic vending machine, so that it can be used in different countries.

5.2. Vending machine generalization After realizing the limitations of the existing vending machine, we plan to make it more general in order to accept all legal currencies, display messages in any languages, and sell any items with fixed prices, such as cigarettes and newspapers. By adding those generic abilities, we can make the generic vending machine suited for most of the desired requirements, since these aspects are the interface between the end users and vending machines. Generalization of the highly modular specification VM has four steps conducted in a descendant way. Its process is illustrated in Fig. 4 and explained below in detail. Vertical arrows denote the extension relationship between data types, for instance DRINK extends MONEY and NAME. The resulting parameterized component GVM is illustrated in Appendix A.

QUARTER MONEY

FQUARTER 4. FMONEY=generalize MONEY through QUARTER by FQUARTER FMONEY

NAME DRINK DRINKLIST VM

3.1 GDRINK=generalize DRINK through MONEY by FMONEY on CONTAINER 3.2 FDRINK=generalize GDRINK through NAME by FNAME 2. FDRINKLIST=generalize DRINKLIST through DRINK by FDRINK on CONVERTER 1. GVM=generalize VM through DRINKLIST by FDRINKLIST on CONTAINER

Fig. 4.

Vending machine generalization.

FNAME FDRINK FDRINKLIST GVM

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

193

Step 1. First, we generalize VM through DRINKLIST using the container constructor. The procedure of semantic generalization is as follows: 1. LOpn = {removeDrinkList, getDrinkList}. 2. OpnAuxDT = {nullDrinkList, eq}. 3. Generalization morphism g : FDRINKLIST → DRINKLIST is defined as: (FdrinkList → DrinkList, nullFDrinkList → nullDrinklist, eqFDrinkList → eq) 4. GVM is defined by renaming DRINKLIST in VM with FDRINKLIST which is created in the next step. Step 2. We generalize DRINKLIST to FDRINKLIST. Its only auxiliary data type DRINK is based on the converter constructor which is preserved during semantic generalization is as follows: 1. LOpn = {remove, getDrink , sum, eq}. 2. OpnAuxDT = {nullDrink , eq, getName, getMoney, count}. 3. Signature morphism g : FDRINK → DRINK is defined as: (Fdrink → Drink , nullFDrink → nullDrink , eqFDrink → eq, getFName → getName, getFMoney → getMoney, countFDrink → count) 2. FDRINKLIST is defined by renaming DRINK in DRINKLIST with FDRINK defined in the next step. Step 3. We generalize DRINK to FDRINK. This step has two parts since the two auxiliary data types in DRINK will be generalized. Step 3.1. First we generalize MONEY to FMONEY. The constructor category in MONEY is preserved during semantic generalization is as follows: 1. LOpn = {canBuy, sum, change, getM oney, eq}. 2. OpnAuxDT = {nullM oney, +, −, grandeq, eq}. 3. Generalization mapping g : FMONEY → MONEY is defined as: (Fmoney → Money, nullFMoney → nullMoney, eqFMoney → eq, + FMoney → +, −FMoney → −, grandeqFMoney → grandeq) 4. GDRINK is defined by renaming MONEY with FMONEY. Step 3.2. We generalize NAME in GDRINK to create the type FDRINK. Syntactic generalization is as follows: 1. LOpn = {getN ame, eq}. 2. OpnAuxDT = {nullN ame, eq}. 3. Signature morphism g : FNAME → NAME is defined as: (Fname → N ame, nullFName → nullName, eqFName → eq) 4. FNAME is defined as follows:

April 13, 2006 9:47 WSPC/117-ijseke

194

00276

S. Sadaoui & P. Yin

spec ELEM = sort Elem end spec FNAME [sort Elem] = Boolean then type Fname[Elem] ::= nullFName pred __eqFName__:Fname[Elem] * Fname[Elem] forall x,y: Fname[Elem] . (x) eqFName (x) . not((x) eqFName (y)) end

5. FDRINK is defined by renaming NAME in DRINK with FNAME. Step 4. Finally, we generalize QUARTER in MONEY to FQUARTER. Syntactic generalization is as follows: 1. LOpn = φ. 2. OpnAuxDT = φ. 3. Signature morphism g : FQUARTER → QUARTER is as: F quarter → Quarter. 4. FQUARTER is defined as: spec FQUARTER [sort Elem] = type Fquarter[Elem] ::= oneQ

end

5. FMONEY is defined by renaming QUARTER by FQUARTER. 5.3. Generic vending machine instantiation Suppose we want to create a vending machine which can sell cigarettes and accept English pounds. The instantiation of the parameterized specification GVM is illustrated in Fig. 5 and explained below. It has four steps conducted in a descendant way. To support the new functionalities, we define two new data types CIGAR and POUND denoting, respectively, cigarettes and English Pounds. from Basic/SimpleDatatypes get Boolean spec CIGAR = Boolean then type Cigar ::= gold | kent| noname pred __eq__: Cigar * Cigar, comm forall x,y: Cigar .(x) eq (x) . not((x) eq (y)) end spec POUND = type Pound ::= oneP end FQUARTER FMONEY

POUND 4. MONEY=instantiate FMONEY through FQUARTER by POUND

FNAME FDRINK FDRINKLIST GVM

MONEY CIGAR

3. DRINK=instantiate FDRINK through {FMONEY,FNAME} by {MONEY,CIGAR} 2. DRINKLIST=instantiate FDRINKLIST through FDRINK by DRINK 1. VMPC=instantiate GVM through FDRINKLIST by DRINKLIST

Fig. 5.

Vending machine instantiation.

DRINK DRINKLIST VMPC

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

195

Step 1. First, we actualize GVM by DRINKLIST defined in the next step. The instantiation morphism list sigM List : [FDRINKLIST → DRINKLIST ] is given in the resulting vending machine VMPC. spec VMPC = GVM [sort FdrinkList] with GVM[Elem] |-> VMPC, FdrinkList[Elem] |-> DrinkList, nullFDrinkList |-> nullDrinkList, eqFDrinkList |-> eq end

Step 2. Data type DRINKLIST is created by instantiating FDRINK in FDRINKLIST. The instantiation mapping list sigMList : [FDRINK → DRINK ] is given in DRINKLIST defined below. Step 3. FDRINK has two formal parameters, FNAME and FMONEY. We use CIGAR to instantiate FNAME and MONEY to replace FMONEY. MONEY is defined in Step 4. The signature morphism list sigMList : [FNAME → CIGAR, FMONEY → MONEY ] is given in DRINK defined as follows. spec DRINKLIST = FDRINKLIST [sort Elem] with FdrinkList[Elem] |-> DrinkList, Fdrink[Elem] |-> Drink, nullFDrink |-> nullDrink, eqFDrink |-> eq, getFName |-> getName, getFMoney |-> getMoney, countFMoney |-> count end spec DRINK = FDRINK [sort Elem] with Fdrink[Elem] |-> Drink, Fmoney[Elem] |-> Money, Fname[Elem] |-> Cigar, nullFMoney |-> nullMoney, eqFMoney |-> eq, plusFMoney |-> +, minusFMoney |-> -, grandeqFMoney |-> grandeq, nullFName |-> nullName, eqFName |-> eq end

Step 4. We finally instantiate FMONEY to MONEY and FQUARTER to POUND. The signature morphism list sigMList : [FQUARTER → QUARTER] is given in MONEY. spec MONEY = FMONEY [sort Elem] with Fmoney[Elem] |-> Money, Fquarter[Elem] |-> Pound end

April 13, 2006 9:47 WSPC/117-ijseke

196

00276

S. Sadaoui & P. Yin

6. Related Work To date, there has been a limited amount of research on component generalization. In [26], generalization consists of transforming a collection of C functions to C++ template functions that operate on arguments with parameterized types. The main idea behind this code generalization approach is the use of the type-inference system of C to discover possibilities for reuse. This kind of generalization is purely syntactic since no constraints are associated with the parameters. Syntactic generalization is much easier to apply on abstract components, such as formal specifications, rather then on code which involves a lot of implementation details. The syntactic generalization approach proposed in [19, 20] does not address the problem of overgeneralization. In contrast, our generalization technique preserves the meaning of the operations being generalized i.e., the original operations still behave as expected in the generic component. Concerning semantic generalization, in [19, 20] a set of axioms are extracted from the rewrite proofs of the properties to be preserved in the generic component. These axioms represent the equations of the formal parameter. We note that [20] is just the application of the generalization technique defined in [19] to the language CASL. In both papers [19, 20], trivial examples have been used. This generalization approach is very difficult to apply to larger examples because complex proofs should be carried out. Our generalization differers completely from this one since a more simple concept, the categorized constructors, is used to build formal parameters. Therefore, our generalization operation is suitable for large scale applications. In addition, our semantic generalization is powerful since it can produce various generic components as opposed to the technique given in [19] which builds only one generic component. 7. Conclusion and Perspectives In this paper, we are motivated by building specifications for reuse through generalization, and specification with reuse through instantiation. There are 2 main contributions of this paper. First, we have defined a number of algorithms for generalization and instantiation of algebraic specifications along with their pre and post conditions. Second, we have proposed to use categorized constructors as a means to control the level of abstraction in generic components. Using these constructors, different generic structures can be obtained from a specific one. The categorized constructors also facilitate the selection and instantiation of components as well as the organization of components in the library. The following future directions further improve our work: • Validating the generic specifications obtained through the generalization process. Validating reusable components is an important task for their reuse. The underlying idea here is to benefit from the validation of the source component as follows: given a property or an equational theorem and its proof in the original component, we want to replay, modulo some transformation, the same proof to ensure

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

197

the correctness of the generic component. To reach this goal, we have first to identify which properties in the source component are required to be preserved in the general one. This idea is inspired by the proof preservation approach proposed in [19]. • Assisting the user in specification generalization and instantiation. To make the generalization operation more effective, guidelines and tools are needed, especially when generalizing highly structured specifications. To date, constructive methods for building correct specifications in a systematic and incremental way are non-existent [18]. In [22], we have provided assistance in the incremental generalization of specifications in the language Act One but without the categorized constructors. Assistance is a set of activities allowing the planning, automation and control of the generalization process. This entire work could be fulfilled with Java which can be used to automate the generalization and instantiation algorithms where some steps are easily implementable and others require user interaction. The same language can also be used to implement a friendly assistance tool which will include both textual and graphical notations. This work will lead to the starting point for the population of generic component libraries.

References 1. D. Aspinall and D. Sannella, From specifications to code in CASL, Algebraic Methodology and Software Technology, 2002, pp. 1–14. 2. L. Baum and M. Becker, Generic components to foster reuse, in Proc. 4th IEEE Int. Conf. on the Technology of Object-Oriented Languages and Systems, TOOLS Pacific, Sydney, Australia, 2000. 3. H. A. Basit, D. C. Rajapakse and S. Jarzabek, Beyond templates: A study of clones in the STL and some general implications, in Proc. Int. Conf. on Software Engineering, ICSE’05, ACM Press, St. Louis, USA. 4. M. Bidoit and P. D. Mosses, CASL User Manual — Introduction to Using the Common Algebraic Specification Language, LNCS 2900, IFIP Series, Springer-Verlag, 2004. 5. Y. Chen and B. H. C. Cheng, Facilitating an automated approach to architecturalbased software reuse, in Proc. 12th Int. Conf. on Automated Software Engineering, 1997. 6. C. Chiang and D. Neubart, Construction reusable specifications through analogy, in Proc. SAC’99, ACM Press, Texas, 1999, pp. 586–592. 7. CoFI (The Common Framework Initiative), CASL Reference Manual, The Complete Documentation of the Common Algebraic Specification Language, LNCS 2960, IFIP Series, Springer-Verlag, 2004. 8. CASL Tool Set: Features. http://www.informatik.uni-bremen.de/cofi/Tools/CATS.html. 9. Heterogeneous Tool Set, http://www.informatik.uni-bremen.de/agbkb/forschung/ formal methods/CoFI/hets/index e.htm. 10. L. Dusink and J. van Katwijk, Reuse dimensions, in Proc. ACM SIGSOFT Symposium on Software Reusability, 1995, pp. 137–149. 11. E. Estevez and P. Fillottrani, Algebraic specifications and refinement for componentbased development using RAISE, J. Computer Science and Technology 2(7) (2002).

April 13, 2006 9:47 WSPC/117-ijseke

198

00276

S. Sadaoui & P. Yin

12. G. T. Heineman and W. T. Council, Component-Based Software Engineering: Putting the Pieces Together, Addison-Wesley, 2001. 13. R. Hinze, Polytypic values possess polykinded types, Science of Computer Programming, 43(2–3), (2002) 129–159. 14. J. Jacky, The Way of Z: Practical Programming with Formal Methods, Cambridge University Press, 1997. 15. J. Jeng and B. H. C. Cheng, A formal approach to reusing more general components, in Proc. Knowledge-Based Software Engineering Conference, 1994, pp. 90–97. 16. D. Kafura, Object-Oriented Software Design and Construction with C++, Vol. 07458, Prentice Hall, New Jersey, 1995. 17. Encyclopedia of Software Engineering, Vols. 1 & 2, Wiley Interscience Publications, 2002. 18. A. van Lamsweerde, Formal specification: A roadmap, in Proc. Conf. on the Future of Software Engineering, Limerick, Ireland, 2000, pp. 147–159. 19. A. M. Moreira, Proof preservation in component generalization, World Congress on Formal Methods 1999:1866, Toulouse, France, Vol. 2, 1999. 20. A. M. Moreira and C. Ringeissen, Generalizing CASL Specification Components and Preserving Rewrite Proofs, Technical Report, INRIA, 2003. 21. C. Paredes and J. L. Fiaderios, Reuse of requirements and specifications (A formal framework), in Proc. Symposium on Software Reusablity, Washington, 1995, pp. 263– 266. 22. S. Sadaoui, Assistance in the generalization of algebraic specifications, in Proc. Int. Conf. on Applied Informatics, Software Engineering, IASTED, Austria, February, 2002. 23. S. Sadaoui, Component generalization with formal methods, in Workshop on Component-Based Software Development Processes ICSR7, April 15–19 . , Texas, 2002. 24. S. Sadaoui and P. Yin, Generalization for component reuse, in Proc. 42nd Annual ACM Southeast Conference, ACMSE, Huntsville, Alabama, April, 2004. 25. S. S. Schneider, The B-Method: An introduction, Cornerstones of Computing Series, Palgrave, 2001. 26. M. Siff and T. W. Reps, Program generalization for software reuse: From C to C++, Foundations of Software Engineering, 1996, pp. 135–146. 27. M. Wirsing, Algebraic description of reusable software components, Technical Report MIP-8816, Fakult¨ at f¨ ur Mathematik und Informatik-Universit¨ at Passau, 1998.

April 13, 2006 9:47 WSPC/117-ijseke

00276

Generalization and Instantiation for Component Reuse

Appendix A: Generic Vending Machine in CASL from Basic/SimpleDatatypes get Boolean from Basic/Numbers get Nat spec ELEM = sort Elem end spec FQUARTER[sort Elem] = type Fquarter[Elem] ::= oneQ end spec FNAME[sort Elem] = Boolean then type Fname[Elem] ::= nullFName pred __eqFName__:Fname[Elem]*Fname[Elem] forall x,y: Fname[Elem] .(x) eqFName (x) .not((x) eqFName (y)) end spec FMONEY[sort Elem]=Boolean and Nat and FQUARTER[sort Elem] then type Fmoney[Elem]::= nullFMoney|add(fmoney[Elem];Fquarter[Elem]) vars m,n:Fmoney[Elem]; c:Fquarter[Elem] op __plusFMoney__:Fmoney[Elem]*Fmoney[Elem]->Fmoney[Elem],comm .(m)plusFMoney(nullFMoney) = m .(nullFMoney)plusFMoney(m) = m .(add(m,c))plusFMoney(n) = add(((m)plusFMoney(n)),c) op __minusFMoney__:Fmoney[Elem]*Fmoney[Elem]->Fmoney[Elem] .(m)minusFMoney(nullFMoney) = m .(m)minusFMoney(m) = nullFMoney type Nat ::= 0|succ(Nat) op countFMoney:Fmoney[Elem]->Nat .countFMoney(add(m,c)) = succ(countFMoney(m)) .countFMoney(nullFMoney) = 0 pred __eqFMoney__:Fmoney[Elem]*Fmoney[Elem] .(nullFMoney)eqFMoney(nullFMoney) .not((nullFMoney)eqFMoney(add(m,c))) .not((add(m,c))eqFMoney(nullFMoney)) .(add(m,c))eqFMoney(add(n,c)) (m)eqFMoney(n) pred grandeqFMoney:Fmoney[Elem]*Fmoney[Elem] .grandeqFMoney(m,m) .grandeqFMoney(add(m,c),nullFMoney) .not(grandeqFMoney((nullFMoney),(add(m,c)))) .grandeqFMoney((add(m,c)),(add(n,c)))grandeqFMoney(m,n) .grandeqFMoney(m,n)=>(add(m,c))minusFMoney(n)=add(((m)minusFMoney(n)),c) end spec FDRINK[sort Elem]= FMONEY[sort Elem] and FNAME[sort Elem] and Boolean then type fdrink[Elem] ::= nullFDrink|create(fmoney[Elem]; fname[Elem]) vars m,m1,m2:Fmoney[Elem]; n,n1,n2:Fname[Elem]; d:Fdrink[Elem] op __+__:Fdrink[Elem]*Fdrink[Elem]->Fdrink[Elem] op getFMoney:Fdrink[Elem]->Fmoney[Elem] . getFMoney(create(m,n)) = m . getFMoney(nullFDrink) = nullFMoney op getFName:Fdrink[Elem] -> Fname[Elem] . getFName(create(m,n)) = n . getFName(nullFDrink) = nullFName

199

April 13, 2006 9:47 WSPC/117-ijseke

200

00276

S. Sadaoui & P. Yin

op change:Fdrink[Elem]*Fmoney[Elem]->Fmoney[Elem] . grandeqFMoney(m2,m1)=>change(create(m1,n),m2)=(m2)minusFMoney(m1) . not(grandeqFMoney(m2,m1))=>change(create(m1,n),m2)=nullFMoney op sum:Fdrink[Elem]->Fmoney[Elem] . sum((create(m1,n1))+(create(m2,n2)))=(m1)plusFMoney(m2) . sum(nullFDrink) = nullFMoney pred __eqFDrink__:Fdrink[Elem]*Fdrink[Elem] .(nullFDrink)eqFDrink(nullFDrink) .not((nullFDrink)eqFDrink(create(m,n))) .(create(m1,n1))eqFDrink(create(m2,n2)) ((m1)eqFMoney(m2))/\((n1)eqFName(n2)) pred canBuy:Fdrink[Elem]*Fmoney[Elem] .canBuy(d,m2)grandeqFMoney(m2,getFMoney(d)) end spec FDRINKLIST[sort Elem]=FDRINK[sort Elem] and Nat and Boolean then type fdrinkList[Elem] ::= nullFDrinkList|addDrink(fdrink[Elem]; fdrinkList[Elem]) vars d,d1,d2:fdrink[Elem]; b,b1,b2:fdrinkList[Elem] op remove:fdrink[Elem]*fdrinkList[Elem]->fdrinkList[Elem] . remove(d,nullFDrinkList) = nullFDrinkList op getDrink:fdrinkList[Elem]->fdrink[Elem] . getDrink(nullFDrinkList) = nullFDrink . getDrink(addDrink(d,b)) = d op sum:fdrinkList[Elem]->Nat . sum(nullFDrinkList) = 0 . sum(addDrink(d,b)) = countFMoney(getFMoney(d))+sum(b) op totalDrink:fdrinkList[Elem]->Nat . totalDrink(addDrink(d,b)) = succ(totalDrink(b)) . totalDrink(nullFDrinkList) = 0 pred __eqFDrinkList__:fdrinkList[Elem]*fdrinkList[Elem] .(nullFDrinkList)eqFDrinkList(nullFDrinkList) .not((nullFDrinkList)eqFDrinkList(addDrink(d,b))) .((b1)eqFDrinkList(b2))/\((d1)eqFDrink(d2)) (addDrink(d2,b2))eqFDrinkList(addDrink(d1,b1)) .(d1)eqFDrink(d2)=>remove(d1,addDrink(d2,b)) = b .not((d1)eqFDrink(d2)) => remove(d1,addDrink(d2,b)) = addDrink(d2,remove(d1,b)) end spec GVM[sort Elem]= FDRINKLIST[sort Elem] then type GVM[Elem] ::= emptyGVM|addDrinkList(FdrinkList[Elem]; GVM[Elem]) op removeDrinkList:FdrinkList[Elem]*GVM[Elem]->GVM[Elem] vars vm,vm1,vm2:GVM[Elem]; d,d1,d2:FdrinkList[Elem] . removeDrinkList(d,emptyGVM) = emptyGVM . removeDrinkList(d,addDrinkList(d,vm)) = vm . not((d1)eqFDrinkList(d2))=>removeDrinkList(d1,addDrinkList(d2,vm)) = addDrinkList(d2,removeDrinkList(d1,vm)) op getDrinkList:GVM[Elem]->FdrinkList[Elem] . getDrinkList(emptyGVM) = nullFDrinkList . getDrinkList(addDrinkList(d,vm)) = d end

Suggest Documents