<<

-Based Programming in C++1

Yannis Smaragdakis Don Batory College of Computing Department of Computer Sciences Georgia Institute of Technology The University of Texas at Austin Atlanta, GA 30332 Austin, Texas 78712 [email protected] [email protected]

Abstract reflect the structure of the design. At the same time, unnecessary dynamic binding can be elimi- Combinations of C++ features, like inheritance, nated, resulting into more efficient implementa- templates, and class nesting, allow for the expres- tions. Unfortunately, this method resulted in very sion of powerful component patterns. In particular, complex parameterizations, causing its inventors to research has demonstrated that, using C++ mixin question its scalability. classes, one can express layered component-based designs concisely with efficient implementations. The mixin layers technique was invented to address In this paper, we discuss pragmatic issues related to these concerns. Mixin layers are mixin classes component-based programming using C++ . nested in a pattern such that the parameter (super- We explain surprising interactions of C++ features class) of the outer mixin determines the parameters and policies that sometimes complicate mixin (superclasses) of inner mixins. In previous work implementations, while other times enable addi- [4][25][26], we showed how mixin layers solve the tional functionality without extra effort. scalability problems of the VanHilst and Notkin method and result into elegant implementations of 1Introduction collaboration-based designs.

Large software artifacts are arguably among the This paper discusses practical issues related to most complex products of human intellect. The mixin-based programming. We adopt a viewpoint complexity of software has led to implementation oriented towards C++ implementations, but our methodologies that divide a problem into manage- discussion is not geared towards the C++ expert. able parts and compose the parts to form the final Instead, we aim to document common problems product. Several research efforts have argued that and solutions in C++ mixin writing for the casual C++ templates (a powerful parameterization mech- programmer. Additionally, we highlight issues that anism) can be used to perform this division ele- pertain to language design in general (e.g., to Java gantly. parameterization or to the design of future lan- guages). Most of the issues clearly arise from the In particular, the work of VanHilst and Notkin interaction of C++ features with the constructs [30][31][32] showed how one can implement col- under study. The discussion mainly stems from laboration-based (or role-based) designs using a actual experience with C++ mixin-based imple- certain templatized class pattern, known as a mixin mentations but a few points are a result of close class (or just mixin). Compared to other techniques examination of the C++ standard, since they refer (e.g., a straightforward use of application frame- to features that no compiler we have encountered works [17]) the VanHilst and Notkin method yields implements. Even though we present an introduc- less redundancy and reusable components that tion to mixins, mixin layers, and their uses, the pri-

1. We gratefully acknowledge the sponsorship of Microsoft Research, the Defense Advanced Research Projects Agency (Cooper- ative Agreement F30602-96-2-0226), and the University of Texas at Austin Applied Research Laboratories.

1 mary purpose of this paper is not to convince To give an example, consider a mixin implement- readers of the value of these constructs. (The ing operation counting for a graph. Operation reader should consult [4], [25], [26], [27], or [30] counting means keeping track of how many nodes for that.) and edges have been visited during the execution of a graph algorithm. (This simple example is one We believe that the information presented here rep- of the non-algorithmic refinements to algorithm resents a valuable step towards moving some pow- functionality discussed in [34]). The mixin could erful programming techniques into the mainstream. have the form: We found that the mixin programming style is quite practical, as long as one is aware of the possi- template class Counting: public Graph { ble interactions with C++ idiosyncrasies. As C++ int nodes_visited, edges_visited; compilers move closer to full implementation of public: the language standard (e.g., some compilers Counting() : nodes_visited(0), already support separate template compilation) the edges_visited(0), utility of such techniques will increase rapidly. Graph() { } node succ_node (node v) { nodes_visited++; 2 Background (Mixins and Mixin Layers) return Graph::succ_node(v); } The term mixin class (or just mixin) has been over- edge succ_edge (edge e) { loaded in several occasions. Mixins were originally edges_visited++; explored in the Lisp language with object systems return Graph::succ_edge(e); like Flavors [21] and CLOS [18]. In these systems, } ... mixins are an idiom for specifying a class and }; allowing its superclass to be determined by linear- ization of . In C++, the term By expressing operation counting as a mixin we has been used to describe classes in a particular ensure that it is applicable to many classes that (multiple) inheritance arrangement: as superclasses have the same (i.e., many different kinds of a single class that themselves have a common of graphs). We can have, for instance, two different virtual base class (see[29],p.402).(Thisisnot the compositions: meaning that we will use in this paper.) Both of Counting< Ugraph > counted_ugraph; these mechanisms are approximations of a general and concept described by Bracha and Cook [6]. The Counting< Dgraph > counted_dgraph; idea is simple: we would like to specify an exten- for undirected and directed graphs. (We omit sion without pre-determining what exactly it can parameters to the graph classes for simplicity.) extend. This is equivalent to specifying a subclass Note that the behavior of the composition is while leaving its superclass as a parameter to be exactly what one would expect: any methods not determined later. The benefit is that a single class affecting the counting process are exported (inher- can be used to express an incremental extension, ited from the graph classes). The methods that do valid for a variety of classes. need to increase the counts are “wrapped” in the mixin. Mixins can be implemented using parameterized inheritance. The superclass of a class is left as a VanHilst and Notkin demonstrated that mixins are parameter to be specified at instantiation time. In beneficial for a general class of object-oriented C++ we can write this as: designs [30]. They used a mixin-based approach to implement collaboration-based (a.k.a. role-based) template designs [5][15][16][22][30]. Role-based designs class Mixin : public Super { are based on the view that objects are composed of ... /* mixin body */ }; different roles that they play in their interaction with other objects. The fundamental unit of func- tionality is a protocol for this interaction, called a

2 collaboration. The mixin-based approach of Van- laboration are represented by inner classes of the Hilst and Notkin results in efficient implementa- layer. Inheritance works at two different levels. tions of role-based designs with no redundancy. First, a layer can inherit entire classes from its Sometimes, however, the resulting parameteriza- superclass (i.e., the parameter of the layer). Sec- tion code is quite complicated (i.e., many mixins ond, inner classes inherit members (variables, need to be composed with others in a complex methods, or even other classes) from the corre- fashion). This introduces some scalability prob- sponding inner classes in the superclass layer. This lems (namely, extensions that instantiate template dual application of inheritance simplifies the parameters can be of length exponential to the implementation of collaboration-based designs, number of mixins composed—see [25]). To make while preserving the benefits of the VanHilst and the approach more practical, by reducing its com- Notkin method. An important source of simplifica- plexity, mixin layers were introduced. Because tions is that inner classes of a mixin layer can refer mixin layers are an incremental improvement of unambiguously to other inner classes—the layer the VanHilst and Notkin method, we only discuss acts as a namespace. implementing collaboration-based designs using mixin layers. We illustrate our point with an example (presented in detail in [25]) of a collaboration-based design Mixin layers [25][26][27] are a particular form of and its mixin layers implementation. (Full source mixins. They are designed with the purpose of code is available, upon request.) This example pre- encapsulating refinements for multiple classes. sents a graph traversal application and was exam- Mixin layers are nested mixins such that the ined initially by Holland [16] and subsequently by parameter of an outer mixin determines the param- VanHilst and Notkin [30]. This application defines eters of inner mixins. The general form of a mixin three different algorithms on an undirected graph, layer in C++ is: all implemented using a depth-first traversal: Ver- tex Numbering numbers all nodes in the graph in template depth-first order, Cycle Checking examines class ThisLayer : public NextLayer { whether the graph is cyclic, and Connected public: Regions classifies graph nodes into connected class Mixin1 : graph regions. The application has three distinct public NextLayer::Mixin1 classes: Graph, Vertex,andWorkspace.TheGraph { ... }; class describes a container of nodes with the usual class Mixin2 : graph properties. Each node is an instance of the public NextLayer::Mixin2 Vertex class. Finally, the Workspace class includes { ... }; the application part that is specific to each graph ... operation. For the VertexNumbering operation, for }; instance, a Workspace object holds the value of the last number assigned to a vertex as well as the Mixin layers are a result of the observation that a methods to update this number. conceptual unit of functionality is usually neither one object nor parts of an object—a unit of func- As shown in Figure 1, we can decompose this tionality may span several different objects and application into five independent collaborations— specify refinements (extensions) to all of them. All one encompassing the functionality of an undi- such refinements can be encapsulated in a single rected graph, another encoding depth-first travers- mixin layer and the standard inheritance mecha- als, and three containing the specifics of each nism can be used for composing extensions. graph algorithm (vertex numbering, cycle check- ing, and connected regions). Note that each collab- This property of mixin layers makes them particu- oration captures a distinct aspect of the application larly attractive for implementing collaboration- and each object may participate in several aspects. based designs. Each layer captures a single collab- That is to say, each object may play several roles. oration. Roles for all classes participating in a col- For instance, the role of a Graph object in the

3 Object Classes Graph Vertex Workspace Undirected Graph- VertexWith- Graph Undirected Adjacencies

Depth First GraphDFT VertexDFT Traversal Workspace- Vertex VertexNumber Numbering Number Workspace- Cycle GraphCycle VertexCycle Checking Cycle Collaborations (Layers) Connected Graph- Vertex- Workspace- Region Connected Connected Connected

Figure 1: Collaboration decomposition of the example application: A depth-first traversal of an undirected graph is specialized to yield three different graph operations. Ovals represent collab- orations, rectangles represent classes, and their intersections represent roles.

“Undirected Graph” collaboration supports storing As shown in [25], such components are flexible and retrieving a set of vertices. The role of the and can be reused and interchanged. For instance, same object in the “Depth First Traversal” collabo- the following composition builds Graph, Vertex, ration implements a part of the actual depth-first and WorkSpace classes nested inside class CycleC traversal algorithm. that implement vertex numbering of undirected graphs using a depth-first traversal:2 By implementing collaborations as mixin layers, the modular design of Figure 1 can be maintained typedef DFT < NUMBER < DEFAULTW < at the implementation level. For instance, the “Ver- UGRAPH>>>CycleC; tex Numbering” collaboration can be implemented using a layer of the general form: By replacing NUMBER with other mixin layers we get the other two graph algorithms discussed. template Many more combinations are possible. We can use class NUMBER : public Next the templates to create classes that implement more { than one algorithm. For instance, we can have an public: class Workspace : application supporting both vertex numbering and public Next::Workspace { cyclecheckingonthesamegraphbyrefiningtwo ... // Workspace role methods depth-first traversals in order: }; typedef DFT < NUMBER < DEFAULTW < class Vertex : UGRAPH>>>NumberC; public Next::Vertex { typedef DFT < CYCLE < NumberC > > CycleC; ... // Vertex role methods }; Furthermore, all the characteristics of an undi- }; rected graph are captured by the UGRAPH mixin

Note that no role (nested class) is prescribed for 2. The DEFAULTW mixin layer is an implementation detail, bor- Graph.AGraph class is inherited from the super- rowed from the VanHilst and Notkin implementation [30]. class of Number (the class denoted by parameter It contains an empty WorkSpace class and its purpose is to Next). avoid dynamic binding by changing the order of composi- tion.

4 layer. Hence, it is straightforward to apply the same checked (code will only be produced for methods algorithms to a directed graph (mixin layer DGRAPH actually referenced in the object code). This means interchanged for UGRAPH):3 that certain errors (including type mismatches and references to undeclared methods) can only be typedef DFT < NUMBER < DEFAULTW < detected with the right template instantiations and DGRAPH > > > NumberC; method calls. Consider the following example:

This technique (of composing source components template in a large number of combinations) underlies the class ErrorMixin : public Super { scalable libraries [3] design approach for source public: code plug-and-play components. ... void sort(FOO foo) { Super::srot(foo); // misspelled 3 Component Programming with C++ Mix- } ins: Pragmatic Considerations };

Since little has been written about the pragmatics If client code never calls method sort,thecom- of doing component programming using C++ mix- piler will not catch the misspelled identifier above. ins (mixin classes or mixin layers), we feel it is This is true even if the ErrorMixin template is necessary to discuss some pertinent issues. Most of used to create classes, and methods other than sort the points raised below concern fine interactions are invoked on objects of those classes. between the mixin approach and C++ idiosyncra- sies. Others are implementation suggestions. They Delaying the instantiation of methods in template are all useful knowledge before one embarks into a classes can be used to advantage, as we will see development effort using C++ mixins and could later. Nevertheless, many common designs are serve to guide design choices for future parameter- such that all member methods of a template class ization mechanisms in programming languages. should be valid for all instantiations. It is not The C++ aspects we discuss are well-documented straightforward to enforce the latter part (“for all and other C++ programmers have probably also instantiations”) but for most practical purposes made some of our observations. Nevertheless, we checking all methods for a single instantiation is believe that most of them are non-obvious and enough. This can be done by explicit instantiation many only arise in the context of component pro- of the template class, which forces the instantiation gramming—that is, when a mixin is designed and of all its members. The idiom for explicit instantia- used in complete isolation from other components tion applied to our above example is: of the system. template class ErrorMixin;

Lack of template type-checking. Templates do When “subtype of” does not mean “substitut- not correspond to types in the C++ language. Thus, able for”. There are two instances where inherit- they are not type-checked until instantiation time ance may not behave the way one might expect in (that is, composition time for mixins). Further- C++. First, constructor methods are not inherited. more, methods of templatized classes are them- Ellis and Stroustrup ([13], p.264) present valid rea- selves considered function templates.4 Function sons for this design choice: the constructor of a templates in C++ are instantiated automatically and superclass does not suffice for initializing data only when needed. Thus, even after mixins are members added by a subclass. Often, however, a composed, not all their methods will be type- mixinclassmaybeusedonlytoenrichoradaptthe method interface of its superclasses without adding 3. This is under the assumption that the algorithms are still data members. In this case it would be quite rea- valid for directed graphs as is the case with the original sonable to inherit a constructor, which, unfortu- code for this example [16]. nately, is not possible. The practical consequence 4. This wording, although used by the father of C++—see [29], p.330—is not absolutely accurate since there is no of this policy is that the only constructors that are automatic type inference. visible in the result of a mixin composition are the

5 ones present in the outer-most mixin (bottom-most ment of this type). Once this is done, the function class in the resulting inheritance hierarchy). To generated by the template can be invoked with make matters worse, constructor initialization lists actual arguments that are subtypes of the corre- (e.g., sponding formal argument types. That is, the fol- constr() : init1(1,2), init2(3) {} ) lowing example (using weird_function, above) is can only be used to initialize direct parent classes. valid code: In other words, all classes need to know the inter- face for the constructor of their direct superclass (if Base base; Mixin derived; they are to use constructor initialization lists). weird_function(base); Recall, however, that a desirable property for mix- // Error if above line omitted! ins is that they be able to act as components: a weird_function(derived); mixin should be implementable in isolation from other parts of the system in which it is used. Thus a But if the third line is omitted, the example single mixin class should be usable with several becomes invalid because the call distinct superclasses and should have as few weird_function(derived) is now illegal—a most dependencies as possible. counterintuitive result.

A possible workaround for this problem is to use a One may question whether the problem arises in a standardized construction interface. A way to do practical setting. Indeed, we encountered the prob- this is by creating a construction class encoding the lem when attempting to build a set of mixin com- union of all possible arguments to constructors in a ponents based on data structure classes from the hierarchy. Then a mixin “knows” little about its Standard Template Library (STL) [28]. The equal- direct superclass, but has dependencies on the ity operator for STL data structures (operator== union of the construction interfaces for all its possi- in C++) is itself a function template of the same ble parent classes. (Of course, another workaround form as weird_function, above. For instance, the is to circumvent constructors altogether by having equality operator for linked lists is defined as: separate initialization methods. This, however, template requires a disciplined coding style to ensure that inline bool operator== methods are always called after object construc- (const list& x, tion.) As a side-note, destructors for base classes const list& y) are called automatically so they should not be rep- { ... } licated. This means that defining mixins (or other sub- The second instance where subtypes are not substi- classes) of STL data structure classes requires tutable in C++ occurs with top-level function tem- redefining operator== for each new class. Again, plates. Assume a function template of the form: this is not very desirable, given that we want mix- ins to act as components with low overhead. Mix- template void weird_function ins should know very little about their superclasses ( Mixin arg ) { ... } and functionality defined for the superclass should be transparently inherited. In practice, several This function template will be instantiated cor- mixin components are just thin wrappers adapting rectly when called with an argument of type their superclass’s interface. Having to redefine Mixin, but not when called with an argu- constructors and top-level function templates may ment of type NewMixin>.Even be overly tedious in this case. though the latter type is a subtype of the former, subtyping is not involved in the function template Synonyms for compositions. In the past sections instantiation policy of C++. The problem is solved we have used typedefs to introduce synonyms for only by ensuring that the template gets instantiated complicated mixin compositions—e.g., Mixin with an argument of type (e.g., there typedefA>Synonym; is an explicit call to weird_function with an argu-

6 Another reasonable approach would be to intro- intermediate layer may specify methods and let the duce an empty subclass: inner-most layer decide whether they are virtual or not. class Synonym : publicA>{}; As we recently found out, this technique was The first form has the advantage of preserving con- described first in [12]. structors of component A in the synonym. The sec- ond idiom is cleanly integrated into the language Single mixin for multiple uses. The lack of tem- (e.g., can be templatized, compilers create short plate type-checking in C++ can actually be benefi- link names for the synonym, etc.). Additionally, it cial in some cases. Consider two classes Base1 and can solve a common problem with C++ template- Base2 with very similar interfaces (except for a based programming: generated names (template few methods): instantiations) can be extremely long, causing compiler messages to be incomprehensible. struct Base1 { void regular() {...} Designating virtual methods. Sometimes C++ ... policies have pleasant side-effects when used in }; struct Base2 { conjunction with mixins. An interesting case is that void weird() {...} of a mixin used to create classes where a certain ... // otherwise same interface as Base1 method can be virtual or not, depending on the }; concrete class used to instantiate the mixin. This is due to the C++ policy of letting a superclass Because of the similarities between Base1 and declare whether a method is virtual, while the sub- Base2, it makes sense to use a single mixin to adapt class does not need to specify this explicitly. Con- both. Such a mixin may need to have methods call- sider a regular mixin and two concrete classes ing either of the methods specific to one of the two instantiating it (a C++ struct isaclasswhose base classes. This is perfectly feasible. A mixin can members are public by default): be specified so that it calls either regular or weird: template struct MixinA : public Super { template void virtual_or_not(FOO foo) { ... } class Mixin : public Super { }; ... public: struct Base1 { void meth1() { Super::regular(); } virtual void virtual_or_not(FOO foo) void meth2() { Super::weird(); } {...} }; ... // methods using “virtual_or_not” }; This is a correct definition and it will do the right struct Base2 { thing for both composition Mixin and void virtual_or_not(FOO foo) {...} Mixin! What is remarkable is that part of }; Mixin seems invalid (calls an undefined method), no matter which composition we decide to per- The composition MixinA designates a form. But, since methods of class templates are class in which the method virtual_or_not is vir- treated as function templates, no error will be sig- tual. Conversely, the same method is not virtual in nalled unless the program actually uses the wrong the composition MixinA. Hence, calls to method (which may be meth1 or meth2 depending virtual_or_not in Base1 will call the method on the composition). That is, an error will be sig- supplied by the mixin in the former case but not in nalled only if the program is indeed wrong. We the latter. have used this technique to provide uniform, com- ponentized extensions to data structures supporting In the general case, this phenomenon allows for slightly different interfaces (in particular, the red- interesting mixin configurations. Classes at an

7 black and hash table of the SGI implementa- template tion of the Standard Template Library [23]). class BINTREE : public Super { public: class Node : public Super::Node { Propagating type information. An interesting Node* parent_link, practical technique (also applicable to languages left_link, right_link ; other than C++) can be used to propagate type public: information from a subclass to a superclass, when ... // Node interface both are created from instantiating mixins. This is a }; common problem in object-oriented program- class Container : ming. It was, for instance, identified in the design public Super::Container { of the P++ language [24] (an extension of C++ Node* header;// Container data members with constructs for component-based program- public: ming) and solved with the addition of the forward ... // Interface methods keyword. The same problem is addressed in other }; }; programming languages (e.g., Beta [20]) with the concept of virtual types. class Comp : public BINTREE < ALLOC < int, Comp > > Consider a mixin layer encapsulating the function- { /* empty /* }; ality of an allocator. This component needs to have type information propagated to it from its sub- Note what is happening in this code fragment classes (literally, the subclasses of the class it will (which is abbreviated but preserves the structure of create when instantiated) so that it knows what actual code that we have used). A binary tree data kind of data to allocate. (We also discussed this structure is created by composing a BINTREE mixin example in detail in [26] but we believe that the layer with an ALLOC mixin layer. The data structure solution presented here is the most practical way to stores integer (int) elements. Nevertheless, the address the problem.) The reason this propagation actual type of the element stored is not int but a is necessary is that subclasses may need to add data type describing the node of a binary tree (i.e., an members to a class used by the allocator. One can integer together with three pointers for the parent, solve the problem by adding an extra parameter to and the two children of the node). This is the type the mixin that will be instantiated with the final of element that the allocator should reserve mem- product of the composition itself. In essence, we ory for. are reducing a conceptual cycle in the parameter- ization to a single self-reference (which is well- The problem is solved by passing the final product supported in C++). This is shown in the following of the composition as a parameter to the allocator code fragment: mixin. This is done through the self-referential (or recursive) declaration of class Comp. (Theoreti- template cally-inclined readers will recognize this as a fix- class ALLOC { point construction.) Note that Comp is just a public: synonym for the composition and it has to use the class Node { EleType element; // stored data type synonym pattern introducing a class (i.e., the public: typedef synonym idiom discussed earlier would ... // methods using stored data not work as it does not support recursion). }; It should be noted that the above recursive con- class Container { struction has been often used in the literature. In protected: FINAL::Node* node_alloc() { the C++ world, the technique was introduced by return new FINAL::Node(); Barton and Nackman [2] and popularized by } Coplien [9]. Nevertheless, the technique is not ... // Other allocation methods mixin-specific or even C++-specific. For instance, }; it was used by Wadler, Odersky and the first author };

8 [33] in Generic Java [7] (an extension of Java with That is, the call to foo from method which_one parametric polymorphism). The origins of the tech- will refer to the global foo, not the foo method of nique reach back at least to the development of F- the Base superclass. bounded polymorphism (e.g., [8]). The main implication of these name resolution Hygienic templates in the C++ standard.The rules is on the way template-based programs C++ standard ([1], section 14.6) imposes several should be developed. In particular, imagine chang- rules for name resolution of identifiers that occur ing a correct class definition into a mixin definition inside templates. The extent to which current com- (by turning the superclass into a template parame- pilers implement these rules varies, but full con- ter). Even if the mixin is instantiated with its super- formance is the best approach to future class in the original code, the new program is not compatibility for user code. guaranteed to work identically to the original, because symbols may now be resolved differently. Although the exact rules are complicated, one can Thismaysurpriseprogrammerswhoworkbycre- summarize them (at loss of significant detail) as ating concrete classes and turning them into tem- “templates cannot contain code that refers to ‘non- plates when the need for abstraction arises. To local’ variables or methods”. Intuitively, “nonlo- avoid the potential for insidious bugs, it is a good cal” denotes variables or methods that do not practice to explicitly qualify references to super- depend on a template parameter and are not in class methods (e.g., Super::foo instead of just scope at the global point closest to the template foo). definition. This rule prevents template instantia- tions from capturing arbitrary names from their Compiler support. Most C++ compilers now have instantiation context, which could lead to behavior good support for parameterized inheritance (the not predicted by the template author.5 technique we used for mixins) and nested classes. We have encountered few problems and mostly A specific rule applies to mixin-based program- with older compilers when programming with C++ ming. To quote the C++ standard (14.6.2), “if a mixins. In fact, most of the compiler dependencies base class is a dependent type, a member of that are not particular to mixin-based programming but class cannot hide a name declared within a tem- concern all template-based C++ programs. These plate, or a name from the templates enclosing include limitations on the debugging support, error scopes”. Consider the example of a mixin calling a checking, etc. We will not discuss such issues as method defined in its parameter (i.e., the superclass they are time-dependent and have been presented of the class it will create when instantiated): before (e.g., [10]). Note, however, that mixin-based programming is not more complex than regular struct Base { template instantiation and typically does not exer- void foo() { ... } cise any of the “advanced” features of C++ tem- }; plates (type inference, higher-order templates, void foo() { } etc.). Overall, the compiler support issues involved in mixin-based programming are about the same as template struct Mixin : public Super { those arising in implementing the C++ Standard void which_one() { foo(); } // ::foo Template Library [28]. }; 4 Related Work Mixin < Base > test; Various pieces of related work have been presented in the previous sections. Here we will discuss approaches that are distinct from ours but seem to follow parallel courses. We cannot exhaustively 5. This is a well-known problem in reference all C++ template-based programming research, first identified by work in hygienic macros [19].

9 techniques but we will selectively mention two References approaches. [1] ANSI / ISO Standard: Programming Languages—C++, ISO/IEC 14882, 1998. The most prominent example is the various imple- mentations of the STL. Such implementations [2] J. Barton and L.. Nackman, Scientific and often exercise the limits of template support and Engineering C++: An Introduction with reveal interactions of C++ policies with template- Advanced Techniques and Applications, based programming. Nevertheless, parameterized Addison-Wesley, 1994. inheritance is not a part of STL implementations. [3] . Batory, V. Singhal, M. Sirkin, and J. Hence, the observations of this paper are mostly Thomas, “Scalable Software Libraries”, ACM distinct from the conclusions drawn from STL SIGSOFT 1993. implementation efforts. [4] D. Batory, R. Cardone, and Y. Smaragdakis, “Object-Oriented Frameworks and Product- Czarnecki and Eisenecker’s generative program- Lines”, 1st Software Product-Line ming techniques [10][11] were used in the Genera- Conference, Denver, Colorado, August 1999. tive Matrix Computation Library (GMCL). Their [5] K. Beck and W. Cunningham, “A Laboratory approach is a representative of techniques using for Teaching Object-Oriented Thinking”, C++ templates as a programming language (that is, OOPSLA 1989,1-6. to perform arbitrary computation at template instantiation time). What sets their method apart [6] G. Bracha and W. Cook, “Mixin-Based from other template meta-programming techniques Inheritance”, ECOOP/OOPSLA 90,303-311. is that it has similar goals to mixin-based program- [7] G. Bracha, M. Odersky, D. Stoutamire and P. ming. In particular, Czarnecki and Eisenecker try Wadler,“Makingthefuturesafeforthepast: to develop components which can be composed in Adding Genericity to the Java Programming multiple ways to yield a variety of implementa- Language”, OOPSLA 1998. tions. Several of the remarks in this paper are [8] P. Canning, W. Cook, W. Hill, W. Olthoff, and applicable to their method, even though their use of J. C. Mitchell, “F-bounded Polymorphism for mixins is different (for instance, they do not use Object-Oriented Programming”, in Proc. mixin layers). Conf. on Functional Programming Languages and Computer Architecture, 1989, 5 Conclusions 273-280. [9] J. Coplien, “Curiously Recurring Template We presented some pragmatic issues pertaining to Patterns”, C++ Report, 7(2):24-27, Feb. mixin-based programming in C++. We believe that 1995. mixin-based techniques are valuable and will [10] K. Czarnecki and U. Eisenecker. Generative become much more widespread in the future. Programming: Methods, Tools, and Mixin-based programming promises to provide Applications. Addison-Wesley, 2000. reusable software components that result into flexi- ble and efficient implementations. [11] K. Czarnecki and U. Eisenecker, “Synthesizing Objects”, ECOOP 1999,18- Previous papers have argued for the value of 42. mixin-based software components and their advan- [12] U. Eisenecker, “Generative Programming in tages compared to application frameworks. In this C++”, in Proc. Joint Modular Languages paper we tried to make explicit the engineering Conference (JMLC’97), LNCS 1204, considerations specific to mixin-based program- Springer, 1997, 351-365. ming in C++. Our purpose is to inform program- [13] M.A. Ellis and B. Stroustrup, The Annotated mers of the issues involved in order to help move C++ Reference Manual, Addison-Wesley, mixin-based programming into the mainstream. 1990.

10 [14] E. Gamma, R. Helm, R. Johnson, and J. [26] Y. Smaragdakis and D. Batory, Vlissides, Design Patterns: Elements of “Implementing Layered Designs with Mixin Reusable Object-Oriented Software. Layers”. In ECOOP 98. Addison-Wesley, 1994. [27] Y. Smaragdakis, “Implementing Large-Scale [15] R. Helm, I. Holland, and D. Gangopadhyay, Object-Oriented Components”, Ph.D. “Contracts: Specifying Behavioral Dissertation, Department of Computer Compositions in Object-Oriented Systems”. Sciences, University of Texas at Austin, OOPSLA 1990, 169-180. December 1999. [16] I. Holland, “Specifying Reusable [28] A. Stepanov and M. Lee, “The Standard Components Using Contracts”, ECOOP Template Library”. Incorporated in ANSI/ 1992, 287-308. ISO Committee C++ Standard. [17] R. Johnson and B. Foote, “Designing [29] B. Stroustrup, The C++ Programming Reusable Classes”, J. of Object-Oriented Language, 3rd Edition, Addison-Wesley, Programming, 1(2): June/July 1988, 22-35. 1997. [18] G. Kiczales, J. des Rivieres, and D. G. [30] M. VanHilst and D. Notkin, “Using C++ Bobrow, The Art of the Protocol. Templates to Implement Role-Based MIT Press, 1991. Designs”. JSSST International Symposium on Object Technologies for Advanced Software, [19] E. Kohlbecker, D. P. Friedman, M. Felleisen, Springer-Verlag, 1996, 22-37. and B. Duba. “Hygienic Macro Expansion”. In Proc. of the SIGPLAN ‘86 ACM Conf. on [31] M. VanHilst and D. Notkin, “Using Role Lisp and Functional Programming, 151-161. Components to Implement Collaboration- Based Designs”. OOPSLA 1996. [20] O.L. Madsen, B. Møller-Pedersen, and K. Nygaard, Object-Oriented Programming in [32] M. VanHilst and D. Notkin, “Decoupling the BETA Programming Language. Addison- Change From Design”, ACM SIGSOFT 1996. Wesley, 1993. [33] P. Wadler, M. Odersky and Y. Smaragdakis, [21] D.A. Moon, “Object-Oriented Programming “Do Parametric Types Beat Virtual Types?”, with Flavors”, OOPSLA 1986. unpublished manuscript, posted in October 1998 in the Java Genericity mailing list [22] T. Reenskaug, E. Anderson, A. Berre, A. ([email protected]). Hurlen, A. Landmark, O. Lehne, E. Nordhagen, E. Ness-Ulseth, G. Oftedal, A. [34] K. Weihe, “A Software Engineering Skaar, and P. Stenslet, “OORASS: Seamless Perspective on Algorithmics”, available at Support for the Creation and Maintenance of http://www.informatik.uni-konstanz.de/ Object-Oriented Systems”, J. of Object- Preprints/ . Oriented Programming, 5(6): October 1992, 27-41. [23] Silicon Graphics Computer Systems Inc., STL Programmer’s Guide.See:http:// www.sgi.com/Technology/STL/ . [24] V. Singhal, A Programming Language for Writing Domain-Specific Software System Generators, Ph.D. Dissertation, Dep. of Computer Sciences, University of Texas at Austin, August 1996. [25] Y. Smaragdakis and D. Batory, “Implementing Reusable Object-Oriented Components”. In the 5th Int. Conf. on Software Reuse (ICSR 98).

11