FC++: Functional Tools for Object-Oriented Tasks
Yannis Smaragdakis and Brian McNamara College of Computing Georgia Institute of Technology Atlanta, GA 30332 {yannis,lorgon}@cc.gatech.edu http://www.cc.gatech.edu/~yannis/fc++
Abstract straightforwardly many common functional opera- tors (a large part of the Haskell Standard Prelude FC++ is a library for programming functionally in [19]). The library is currently quite rich in func- C++. Compared to other C++ functional program- tionality and has an efficient implementation. ming libraries, FC++ is distinguished by its power- ful type system which allows manipulating In a previous paper [16], we introduced FC++ and parametrically polymorphic functions (e.g., pass- its innovative type system, showed the components ing them as arguments to other functions and of the library, and demonstrated how its implemen- returning them as results). tation is more efficient than previous similar attempts. In this paper we show how to leverage In this paper, we show how FC++ can be used in the library to create simple, efficient, and safe common OO programming tasks. We demonstrate implementations of common OO design patterns FC++ implementations of several common design [8]. patterns (Adapter, Builder, Command, and more). Compared to conventional C++ implementations Certainly a lot has been written about language of these patterns, our implementations are either support for implementing design patterns (e.g., simpler (in that fewer classes/dependencies are [4][6]), functional techniques in OO programming, needed), more efficient, or more type-safe (thanks etc. Some of the approaches in the literature are to parametric polymorphism and type-inference). even very close in philosophy to our work. For instance: 1 Introduction • Alexandrescu [2] demonstrates how the meta- Functional and object-oriented programming are programming capabilities of the C++ language the most active fields of research in programming can be used to yield elegant pattern implemen- languages and methodologies. Several pieces of tations. work have attempted to connect the two paradigms. • Kühne’s dissertation proposes several patterns Among them are the Pizza language [18], extend- inspired by functional programming [14]. ing Java, as well as libraries for programming func- • Using functional techniques (higher-order tionally in C++ [11][12][15][21]. FC++ [16] is one functions) to implement the Observer and such library, distinguished from all others by its Command patterns is common—in fact, even powerful type system: FC++ allows the program- standard practice in Java and Smalltalk. mer to define and fully manipulate parametrically • The benefits of polymorphic and higher-order polymorphic functions. The conventional C++ way functions have often been discussed in the of representing polymorphic functions is via func- functional programming literature [22]. tion templates (e.g., see the C++ Standard Library Therefore, by necessity, part of our material is not [20]). Nevertheless, function templates suffer conceptually novel. In particular, Section 3 shows severe limitations—e.g., they cannot be passed as that FC++ offers a rich framework for OO tasks, parameters to other functions or returned as results. but similar results can be obtained with other lan- FC++ polymorphic functions overcome these limi- tations. This allows FC++ to re-implement
1 guages or libraries (although, among C++ and return them as results—even if they are poly- approaches, FC++ is arguably the most complete). morphic. There are two kinds of functoids: direct and indirect. Direct functoids are the usual repre- Section 4, however, shows new implementations of sentation for functions in FC++. Direct functoids common patterns by concentrating on some of the can be either monomorphic or polymorphic. Indi- more novel elements of FC++—mainly type infer- rect functoids, on the other hand, must always be ence and its ability to manipulate polymorphic monomorphic but can express first-class functions. functions. We see how parametric polymorphism That is, with indirect functoids, we can define vari- can find its way into some design patterns, how ables that range over all functions with the same FC++ can handle such tasks, and how using para- type signature. Thus, indirect functoids can be metric polymorphism results into more generic viewed as indirect function references, much like code. [Note that we do not discuss improvements C/C++ function pointers. In addition to direct and in design patterns’ implementations by the mere indirect functoids, FC++ provides a number of use- addition of parametric typing (e.g., C++ class tem- ful operations for creating functoids, composing plates) in a language. These are well understood them, specializing them, etc. We shall now discuss and are even discussed in [8], as implementation a few of the key components of FC++ in more suggestions.] detail.
Although some C++ background is required for Indirect functoids are represented as the FunN fam- much of the paper, we believe that the principles ily of classes. FunNs specify function signatures via are interesting even to non-C++ programmers. In template parameters; N is the number of arguments. particular, the paper offers insights for language For example, Fun2
In FC++, we express functions as instances of Note that f’s behavior depends on which functoid classes that follow certain conventions. We call it is bound to. This may seem reminiscent of OO such classes functoids. The key advantage to using dynamic dispatch (where a method call depends functoids (rather than C++ functions or function upon the dynamic type of the object that the templates) is that we can pass them as parameters receiver is bound to), and rightly so! There is just
2 such a virtual method call buried inside the imple- the int 3, and whose second field is the char ‘c’. mentation of all indirect functoids. Indeed, the C++ standard defines a template func- tion for the same purpose, which goes by the name Indirect functoids are more versatile than function std::make_pair. However, compared to mk_pair, pointers: they employ automatically currying, they std::make_pair suffers extreme limitations, by can be bound to new function objects that are cre- virtue of being defined as a template function. ated on-the-fly, and they exhibit a form of subtype Template functions cannot be passed as parame- polymorphism (see [16]). What follows will dem- ters, which means we cannot use the functional onstrate some of these features, which have impor- techniques mentioned above (i.e., currying and tant applications in Section 3 and Section 4. composition) on templates. Direct functoids avoid Currying is a functional technique that allows us to these limitations. For example, we can say curry2( mk_pair, 3 ) bind a subset of a function’s arguments to specific to return a new direct functoid which takes one values. For example, we can use curry to bind the argument of any type T, and returns a first argument of f to the value 1, creating a new std::pair
Although this simpler form is what a typical FC++ struct MkPair { user would write, we will avoid it in this paper, in template
3 This encoding mechanism is the key that allows functoids f and g of types F and G, respectively. FC++ to create higher-order functoids that can compose(f,g) returns a (possibly polymorphic) directly manipulate polymorphic functoids. Specif- direct functoid with the following Sig member: ically, other functoids can determine what the result type of a particular polymorphic functoid template
4 use of subtype polymorphism. Subtype polymor- Here is a brief example which illustrates how Com- phism allows code that operates on a certain class mand might be employed in a word-processing or interface to also work with specializations of the application: class or interface. This is analogous to higher-order functions: the holder of an object reference may class Command { public: express a generic algorithm which is specialized virtual void execute()=0; dynamically based on the value of the reference. }; Encapsulating functionality and data as an object is analogous to direct function manipulation. Other class CutCommand : public Command { code can operate abstractly on the object’s inter- Document* d; public: face (e.g., to adapt it by creating a wrapper object). CutCommand(Document* dd) : d(dd) {} void execute() { d->cut(); } It has long been identified that functional tech- }; niques can be used in the implementation of design patterns. For instance, the Visitor pattern is often class PasteCommand : public Command { considered a way to program functionally in OO Document* d; languages. (The interested reader should see [13] public: and its references for a discussion of Visitor.) The PasteCommand(Document* dd) : d(dd) {} void execute() { d->paste(); } Smalltalk class MessageSend (and its variants, see }; [3], p.254), the C++ Standard Library functors, Alexandrescu’s framework ([2], Ch. 5), etc., are all Document d; trying to capture the generic concept of a “func- ... tion” and use it in the implementation of the Com- Command* menu_actions[] = { new CutCommand(&d), mand or Observer pattern. Here we will briefly new PasteCommand(&d), review some of these well-known techniques, from ... the FC++ standpoint, by using indirect functoids. }; ... Command. The Command pattern turns requests menu_actions[choice]->execute(); into objects, so that the requests can be passed, The abstract Command class exists only to define the stored, queued, and processed by an object which interface for executing commands. Furthermore, knows nothing of either the action or the receiver the execute() interface is just a call with no argu- of the action. An example application of the pattern ments or results. In other words, the whole com- is a menu widget. A pull-down menu, for instance, mand pattern simply represents a “function must “do something” when an option is clicked; object”. From a functional programmer's perspec- Command embodies the “something”. Command tive, Command is just a class wrapper for a “lambda” objects support a single method (usually called or “thunk”—an object-oriented counterpart of a execute). Any state that the method operates on functional idiom. Indirect functoids in FC++ repre- needs to be captured inside a command object. sent such function-objects naturally: a Fun0
5 In this last code fragment, all of the classes that the receivers—their ability to receive updates—is comprised the original design pattern implementa- encapsulated as a Fun0
6 interface: a function call which takes no argument tion as a function and causes the computation to and returns nothing. occur only when the function is actually called (i.e., when the result is needed). For instance, in C++'s parameterization mechanism lets us extend FC++ a call foo(a,b) can be delayed by writing it this notion to functions which take arguments and as curry2(foo, a, b). The latter expression will return values. For example, consider an observer- return a 0-argument functoid that will perform the like scenario, where the notifier passes a value (for original computation, but only when it is called. instance, a string) to the observer's update method, Thus, passing this functoid around enables it to be and the update returns a value (say, an integer). evaluated lazily. This can be solved using the same strategy as before, but using a Fun1
7 in its type system—it has nothing new to offer to a impossible to modify pre-compiled code, or it dynamically typed language, like Smalltalk.) may be tedious to manipulate existing inherit- ance hierarchies, or the commonalities cannot 4.1 Parametric vs. Subtype Polymorphism be isolated due to language restrictions (e.g., Design patterns are based on subtype polymor- no multiple inheritance, no common interface phism—the cornerstone of OO programming. signature). Even in languages like Java where a Parametric polymorphism, on the other hand, is not supertype of all types exists (the Object type), commonly available in OO languages, and, even problems arise with higher-order polymorphic when it is, its power is limited (e.g., there is no type functions, like our curry operator. The prob- inference capability). FC++ adds this capability to lem is that an Object reference may be used to C++. It is interesting to ask when parametric poly- point to any object, but it cannot be passed to a morphism can be used in place of subtype poly- function that expects a reference of a specific morphism and what the benefits will be, especially (but unknown) type. Thus, implementing a in the context of design patterns. fully generic curry with subtype polymor- phism is impossible. Parametric polymorphism is a static concept: it • Type checking is static. With subtype polymor- occurs entirely at compile time. Thus, to use a phism, errors can remain undetected until run- parametrically polymorphic operation, we need to time. Such errors arise when an object is know the types of its arguments at each invocation assumed to be of a certain dynamic type but is site of the operation (although the same operation not. Since the compiler can only check the can be used with many different types of argu- static types of objects, the error cannot be ments). In contrast, subtype polymorphism sup- detected at compile-time. In fact, for many of ports dynamic dispatch: the exact version of the the most powerful and general polymorphic executed operation depends on the run-time type of operations, subtype polymorphism is impossi- the object, which can be a subtype of its statically ble to use with any kind of type information. known type. For instance, it would be impossible to imple- ment a generic compose operator with subtype Therefore a necessary condition for employing polymorphism, unless all functions composed parametric polymorphism is to statically know the are very weakly typed (e.g., functions from type of operands of the polymorphic operation at ObjectstoObjects). The same is true with each invocation site. When combined with type most other higher-order polymorphic opera- inference, parametric polymorphism can be as con- tions (i.e., functions that manipulate other venient to use as subtype polymorphism and can be functions). advantageous for the following reasons: • Method dispatch is static. Despite the many • No common supertype is required. The issue of techniques developed for making dynamic dis- having an actual common superclass or just patch more efficient, there is commonly a run- supporting the right method signature is simi- time performance cost, especially for hard-to- lar to the named/structural subtyping dilemma. analyze languages like C++. Apart from the All mainstream OO languages except Small- direct cost of dynamic dispatch itself, there is talk use named subtyping: a type A needs to also an indirect cost due to lost optimization declare that it is a subtype of B. In contrast, in opportunities (such as inlining). structural subtyping, a type A can be a subtype 4.2 Pattern Examples of type B if it just implements the right method signatures. The advantage of requiring a com- Adapter. The Adapter pattern converts the inter- mon superclass is that accidental conformance face of one class to that of another. The pattern is is avoided. The disadvantage is that sometimes often useful when two separately developed class it is not easy (or even possible) to change the hierarchies follow the same design, but use differ- source code of a class to make it declare that it ent names for methods. For example, one window is a subtype of another. For instance, it may be toolkit might display objects by calling paint(),
8 while another calls draw(). Adapter provides a tion time instead of the update time. A better way to adapt the interface of one to meet the con- approach is: straints of the other. compose( Adaptation is remarkably simple when a functional curry2(ptr_to_fun(&AnObserver::update), design is followed. Most useful kinds of method this), ptr_to_fun(current_time)) adaptation can be implemented using the currying and functoid composition operators of FC++, with- In this example we combined currying with func- out needing any special adapter classes. These tion composition in order to specialize the inter- adaptation operators are very general and reusable. face. The resulting function takes no arguments but uses global state (returned by the current_time() Consider the Command or the Observer pattern. As routine) as the value of the argument of the update we saw, in an FC++ implementation there is no method. In this way, each update will be times- need for abstract Observer or Command classes. tamped with the value of the system clock at the More interestingly, the concrete observer or com- time of the update! mands do not even need to support a common interface—their existing methods can be converted Other parametric polymorphism approaches (e.g., into functoids. Nevertheless, this requires that the the functional part of the C++ Standard Library existing methods have the right type signature. For [20], or Alexandrescu’s framework for functions instance, in our ConcreteObserver example, [2], Ch.5) support currying and composition for above, the be_notified method was used in place monomorphic functions. The previous examples of a conventional update method, but both meth- demonstrate the value of type inference, which is ods have the same signature: they take no argu- not unique to FC++. Nevertheless, FC++ also ments and return no results. What if an existing extends type inference to polymorphic functions. method has almost the right signature, or if meth- We will see examples of currying and composition ods need to be combined to produce the right sig- of polymorphic operations in the implementations nature? of the next few patterns.
For an example, consider a class, AnObserver, that Decorator. The Decorator pattern is used to attach defines a more general interface than what is additional responsibilities to an object. Although expected. AnObserver may define a method: this can happen dynamically, most of the common void update(Time timestamp) { ... } uses of the Decorator pattern can be handled stati- cally. Consider, for instance, a generic library for We would like to use this method to subscribe to the manipulation of windowing objects. This some other object’s service (which we will call the library may contain adapters, wrappers, and com- publisher) that will issue periodic updates. As binators of graphical objects. For example, one of shown in the Observer pattern implementation, the its operations could take a window and annotate it publisher expects a functoid object taking no argu- with vertical scrollbars. The problem is that the ments. This is easy to effect by adapting the generic library has no way of creating new objects observer’s interface: for applications that may happen to use it. The generic code does not share an inheritance hierar- curry2(ptr_to_fun(&AnObserver::update), chy with any particular application, so it is impos- this, current_time()) sible to pass it concrete factory objects (as it cannot (recall that curry2 is the currying function for 2- declare references to an abstract factory class). argument functoids.) In the above, we used a con- stant value (the current time) to specialize the This problem can be solved by making the generic operations be parametrically polymorphic and update method so that it conforms to the required interface. That is, all update events will get the enabling type inference. For instance, we can write same timestamp—one that indicates the subscrip- a generic FC++ functoid that will annotate a win- dow with a scrollbar:
9 struct AddScrollbar { operation, prints the result of the invocation template
10 In the Builder pattern, the Director object often engine does not change in the middle of the inter- implements a method of the form: pretation. Thus, the pattern is static—another rea- son to prefer parametric polymorphism to void construct(ObjCollection objs) { subtyping. This may result in improved perfor- for all objects in objs{ if (object is_a A) mance because the costs of dynamic dispatch are builder->build_part_A(object); eliminated. else if (object is_a B) builder->build_part_B(object); The new organization also has other benefits. First, ... the control flow of the pattern is simpler: the client } never calls the Builder object directly. Instead of } the get_result call, the results are returned by the (Pseudocode shown in italics.) Note that the construct call made to the Director. Second, build_part method of the builder objects returns Directors can now be more sophisticated: they can, no result. Instead, the Builder object aggregates the for instance, declare temporary variables of the results of each build_part operation and returns same type as the type of the Builder’s product. them through a method (we will call it These can be useful for caching previous products, get_result). This method is called by a client without cooperation from the Builder classes. object (i.e., not the Director!). Additionally, Directors can now decide when the data should be consumed by the client. For A more natural organization would have the Direc- instance, the Observer pattern could be used: cli- tor collect the products of building and return them ents of an HTML interpreter could register a call- to the client as a result of the construct call. In an back object. The Director object (i.e., the extreme case, the get_result method could be interpreter) can then invoke the callback whenever unnecessary: the Director could keep all the state data are to be consumed. Thus, the construct (i.e., the accumulated results of previous method may only be called once for an entire docu- build_part calls) and the Builder could be state- ment, but the client could be getting data after each less. Nevertheless, this is impossible in the original paragraph has been interpreted. implementation of the pattern. The reason for keeping the state in the Builders is that Directors Another observation is that the Director class can have no idea what the type of the result of the be replaced by a functoid so that it can be manipu- build_part method might be. Thus, Directors lated using general tools. Note that the Director cannot declare any variables, containers, etc. based class in the Builder pattern only supports a single on the type of data returned by a Builder. Gamma method call. Thus, it can easily be made into a et al. [8] write: “In the common case, the products functoid. Calling the functoid will be equivalent to produced by the concrete builders differ so greatly calling construct in the original pattern. The in their representation that there is little to gain return type of the functoid depends on the type of from giving different products a common parent builder passed to it as an argument (instead of class.” being void). An example functoid which integrates these ideas is shown here: This scenario (no common interface) is exactly one where parametric polymorphism is appropriate struct DoBuild { template
11 for all objects in objs { studied. Their conclusion was that meta-object pro- if(object is_a A) tocols should be added to OO languages for better c.add(b.build_part_A(object)); pattern support. Thus, Alexandrescu’s implementa- else if (object is_a B) c.add(b.build_part_B(object)); tion is a great demonstration of the meta-program- ... ming capabilities of C++—the language’s ability to } perform template computation on static properties return c; can often be used instead of meta-object protocols. } } do_build; Géraud and Duret-Lutz [9] offer some arguments for redesigning patterns to employ parametric With this approach, the “director” functoid is in polymorphism. Thus, they propose that parametric full control of the data production and consump- polymorphism be part of the “language” used to tion. The Director can be specialized via currying specify patterns. In contrast, our approach is to use to be applied to specific objects or to use a specific parametric polymorphism with type inference in Builder. Two different Directors can even be com- the implementation of patterns. From an imple- posed—the first building process can assemble a mentation standpoint, the Géraud and Duret-Lutz builder object for the second! suggestions are not novel: they have long been 5 Related Work used in C++ design pattern implementations. Fur- thermore, the examples we offer in this paper are We have referred to related work throughout the more advanced, employing type inference and previous sections. Here we will selectively discuss manipulation of polymorphic functions. only some particularly related work that we did not The Pizza language [18] integrates functional-like get the chance to analyze earlier. support to Java. This support includes higher-order There are several libraries that add functional pro- functions, parametric polymorphism, datatype defi- gramming features to C++. Some of them nition through patterns, and more. Pizza operates [11][12][21] focus on front-end support (e.g., a as a language extension and requires a pre-com- lambda keyword) for creating functions on-the-fly. piler. Support for parametric polymorphism in Java Other libraries [15][20] provide reusable function- has been a very active research topic (e.g., ality without any special front-end support. FC++ [1][5][17][23]). Type inference is not a part of [16] is in this latter category: it provides mecha- most approaches, but is used at least in GJ [5]. nisms for expressing higher order and polymorphic Nevertheless, due to the GJ translation technique functions, but does not hide the implementation (erasure) it does not seem possible to extract static behind a more convenient front end. FC++ is dis- type information nested inside template parame- tinguished from the rest by its full type system for ters. Thus, it is not possible to use the GJ type sys- polymorphic functions, which enables creating and tem to pass polymorphic functions as arguments manipulating polymorphic functions on-the-fly, and return them as results (in a type-safe way). and by its support for indirect function references. It should be noted that Java inner classes [10] are Dami’s currying mechanism for C/C++ [7] was excellent for implementing higher-order functions. used to demonstrate the advantages of function Inner classes can access the state of their enclosing specialization, but required a language extension. class, and, thus, can be used to express closures— As we saw, the same benefits can be obtained in automatic encapsulations of a function together C++ without extending the language. with the data it acts on. Java inner classes can be anonymous, allowing them to express anonymous Alexandrescu [2] offers a mature C++ implementa- functions—a capability that is not straightforward tion of the Abstract Factory pattern. His approach to emulate in C++. Many of our observations of consists of a generic (i.e., polymorphic) Abstract Section 3 also apply to Java. In fact, the most com- Factory class that gets parameterized statically by mon Java implementations of the Command and all the possible products. It is worth noting that this is the exact scenario that Baumgartner et al. [4]
12 Observer design patterns use inner classes for the Programming Systems, Languages, and commands/callbacks. Applications (OOPSLA) 1998. [6] C. Chambers, B. Harrison, and J. Vlissides, 6 Conclusions “A Debate on Language and Tool Support for Design Patterns”, ACM Symposium on In this paper we examined how functional tech- Principles of Programming Languages, 2000 niques in general, and FC++ in particular, can be (PoPL 00). applied to OO tasks, by illustrating the implemen- tations of some common design patterns. Our [7] L. Dami, “More Functional Reusability in C/ examples from Section 3 are similar to others in the C++/Objective-C with Curried Functions”, Object Composition, Centre Universitaire literature, but, to our knowledge, our example pat- d’Informatique, University of Geneva, pp. 85- tern implementations from Section 4 have not 98, June 1991. appeared before, even in different contexts. Addi- tionally, we are not aware of another mainstream, [8] E. Gamma, R. Helm, R. Johnson, and J. statically-typed OO language with the capabilities Vlissides, Design Patterns: Elements of of FC++ for manipulating polymorphic functions Reusable Object-Oriented Software. Addison-Wesley, 1994. and employing type inference. [9] T. Géraud and A. Duret-Lutz, “Generic Our implementations demonstrate the value of Programming Redesign of Patterns”, in Proc. parametric polymorphism and type inference (even European Conf. on Pattern Languages of in a rather primitive form) in a statically-typed Programs, 2000 (EuroPLoP’2000). object-oriented language. By selectively using [10] Javasoft, Java Inner Classes Specification, parametric polymorphism with type inference and 1997. In http://java.sun.com/products/ higher-order functions, we can create simple, yet jdk/1.1/docs/. general, implementations of patterns that are both efficient and type safe. [11] J. Järvi and G. Powell, “The Lambda Library: Lambda Abstraction in C++”, TUCS Tech. Report No. 378, November 2000, available References from http://www.tucs.abo.fi/ [1] O. Agesen, S. Freund, and J. Mitchell, publications/techreports/TR378.html. “Adding Type Parameterization to the Java [12] O. Kiselyov, “Functional Style in C++: Language”, Proc. Object-Oriented Closures, Late Binding, and Lambda Programming Systems, Languages, and Abstractions”, poster presentation, Int. Conf. Applications (OOPSLA) 1997, 49-65. on Functional Programming, 1998. See also: [2] A. Alexandrescu, Modern C++ Design: http://www.lh.com/~oleg/ftp/ . Generic Programming and Design Patterns [13] S. Krishnamurthi, M. Felleisen, D. P. Applied, Addison-Wesley Professional, 2001. Friedman, “Synthesizing Object-Oriented and [3] S.R. Alpert, K. Brown, B. Woolf, The Design Functional Design to Promote Re-Use”, Patterns Smalltalk Companion, Addison- European Conference on Object-Oriented Wesley, 1998. Programming (ECOOP), Brussels, Belgium, July 1998. [4] G. Baumgartner, K. Läufer, V.F. Russo, “On the Interaction of Object-Oriented Design [14] T. Kühne, A Functional Pattern System for Patterns and Programming Languages”, Tech. Object-Oriented Design, Verlag Dr. Kovac, Report CSD-TR-96-020, Dept. of Comp. Sci., Hamburg, 1999. Purdue University, February 1996. [15] K. Läufer, “A Framework for Higher-Order [5] G. Bracha, M. Odersky, D. Stoutamire and P. Functions in C++”, Proc. Conf. Object- Wadler, “Making the future safe for the past: Oriented Technologies (COOTS), Monterey, Adding Genericity to the Java Programming CA, June 1995. Language”, Proc. Object-Oriented [16] B. McNamara and Y. Smaragdakis, “FC++: Functional Programming in C++”, Proc.
13 International Conference on Functional Programming (ICFP), Montreal, Canada, September 2000. [17] A. Myers, J. Bank and B. Liskov, “Parameterized Types for Java”, ACM Symposium on Principles of Programming Languages, 1997 (PoPL 97). [18] M. Odersky and P. Wadler, “Pizza into Java: Translating theory into practice”, ACM Symposium on Principles of Programming Languages, 1997 (PoPL 97). [19] S. Peyton Jones and J. Hughes (eds.), Report on the Programming Language Haskell 98, available from www.haskell.org, February 1999. [20] A. Stepanov and M. Lee, “The Standard Template Library”, 1995. Incorporated in ANSI/ISO Committee C++ Standard. [21] J. Striegnitz, “FACT!—The Functional Side of C++”, http://www.fz-juelich.de/zam/FACT [22] S. Thompson, “Higher-order + Polymorphic = Reusable”, unpublished, May 1997. Available at: http://www.cs.ukc.ac.uk/pubs/1997/224 [23] K. Thorup, “Genericity in Java with Virtual Types”, European Conference on Object- Oriented Programming (ECOOP) 1997, 444- 471.
14