<<

Appeared in ++ Report, Vol 9 #9, pages 32–42, October 1997

The Object Pattern

Thomas Kuhne¨ ([email protected]) Department of Computer Science, TU Darmstadt Magdalenenstr. 11c, -64289 Darmstadt

1 Introduction mand) are passed as constructor arguments. In addition, a accepts further argu- The Function Object pattern can be regarded ments after creation from any client it was passed as a variation to the that to and with all benefits of partial parameterization takes parameters and returns a result. The (see section 2.3). pattern describes how to build encapsulated The following section not only explains a design components for behavior parameterization, func- technique but deliberately uses many examples to tion reuse, calculation on demand, representing illustrate the various usages of Function Object. “business-transactions”, and first-class behavior, Section 3 then attempts to explain Function Ob- e.g., protocol-, undo-, and persistence mecha- ject’s implications for software reuse by enumerat- nisms. In contrast to Command, Function Ob- ing the abstract concepts involved. ject establishes a useful collaboration with itera- tors. We show in particular how to use generic function objects with iterators in order to al- Function Object low multi-dispatching operations on heterogeneous 2 Pattern: data structures. Function Object belongs to the class of design 2.1 Intent patterns that describe how to compensate for miss- Encapsulate a function with an object. This is ing language features. For instance, Convenience useful for parameterization of algorithms, partial Methods [7] shows how to emulate default parame- parameterization of functions, delayed calculation, ters and Visitor [5] is less needed in languages with lifting methods to first-class citizens, and for sep- multi-dispatch. Function Object describes how to arating functions from data. achieve the benefits that programmers gain from blocks (and functional programmers gain from higher-order functions) in object-oriented lan- 2.2 Also Known As guages without such a feature. Very similar to the Command pattern [5] Function Object objectifies Lexical Closure [2], Functor [4], Agent [6], behavior and thus opens up many useful applica- Agent-Object [8], Functionoid [3], Functoid [10], tions (see section 2.4) which go even beyond the Function-Object [14]. potential of Smalltalk blocks (see section 2.9.4). As Command and Strategy [5] Function Object de- fines behavior that is not tied to a particular data 2.3 Motivation abstraction. So-called free functions usually do not occur during domain analysis. They resemble so- Behavior parameterization occurs in almost every called design-objects [12], like iterator objects, and program. Iterators are a good example. The it- handler. eration algorithm is constant whereas an iteration Technically commands and function objects can action or function varies. A special of itera- be called closures. A closure is a function that on tion is the has (member test) function of an col- creation is able to capture variables values from lection. Consider a collection of books. Member its environment. In case of Command the environ- testing should cover testing for a particular book ment variables (e.g., the text for an editor com- title, book author, book type, etc.

1 2.3.1 Problem lump all functions in one class. Second, we have to apply heavy renaming for iteration schemes and One way to do this is to use an external itera- functions in the subclass; any combination of iter- tor. Then the varying predicate (compare title, ation scheme and function must be given a distinct compare author, etc.) can be combined with the name. Third, we lose the ability to use dynamic traversal algorithm by placing the predicate in an binding for the selection of a function. Since all explicit loop that advances the external iterator functions belong to one class, we no longer can use one by one. As a result, the number of explicit concrete ITERATOR instances to select the actual loops corresponds to the number of member test combination of iteration and function. predicates. However, there are good reasons to write such a Awkward Reuse. Reusing the functions for other loop only once (see, e.g., the discussion in the Iter- iteration schemes or different purposes is practi- ator pattern [5]). Consequently, we use an internal cally impossible if they are defined in ITERATOR iterator. Given a predicate, it returns true if any subclasses. The solution is to extract the func- of the books fits the predicate. Here is how the tions in classes of their own. But now multiple predicate is “given” to the internal iterator con- inheritance is necessary in order to inherit from ventionally: ITERATOR and to inherit from a particular func- tion. At least multiple tests or functions can be The actual member test method is a Template “mixed-in”, but scope resolution is needed, and Method [5], which depends on an abstract predi- each function combination results in a combinator cate. The implementation for the abstract predi- subclass. cate, and thus the specific member test operation, is given in descendants [12]. Selection of the mem- Poor encapsulation. Composing an iteration ber tests is done by selecting the appropriate de- scheme and a function with inheritance joins the scendant. So, traversal algorithm and functions name spaces of both. In fact, the multiple inheri- in general are combined through dynamic binding tance solution causes iterator, function, and com- of the abstract function method. Note that this binator class to share the same name-space. Im- forces us to place the member test method outside plementation changes to either of the classes can the collection of books (e.g., at iteration objects) easily invalidate the other. An between since we do not want to create book collection sub- super- and subclasses, as the private parts in C++, classes but member test variations only. Further alleviates the problem considerably. disadvantages aligned with the above application of an object-oriented design, using inheritance and Unrestricted flexibility. Creating a designated class dynamic binding are: for the combination of an iteration scheme and a function opens up the possibility of overriding the Static combination. All possible combinations of iteration scheme for particular actions. Explicitly iteration schemes and functions are fixed at com- counting the elements in a collection could be re- pile time. Neither is it possible to create a new placed by just returning the value of an attribute function at run time. count. Unfortunately, this advantage for the de- signer of a library is a disadvantage for the user of Combinatorial explosion. Sometimes it is useful to a library. The user may rely on properties of the select not just one, but a combination of functions original iteration scheme. If the iteration function or tests and functions. With subclassing, it is not not only counts the elements, but in addition pro- feasible to provide any independent combination, duces some side-effect, the side-effects will not be since it leads to an exponentially growing number executed in the optimized version described above. of subclasses. Identity changes. In order to change the iteration Subclass proliferation. Each new function demands function a different iterator instance must be used. a new subclass of ITERATOR. The name space for While one would seldom need to rely on an un- classes is cluttered by many concrete ITERATOR changing iterator instance, this property is inhibit- subclasses. We may combine all functions in one ing in other settings of parameterization. For in- subclass using repeated inheritance, but this only stance, it might be mandatory to keep the same makes things worse. First, it is non-local design to

2 instance of a cook, while being able to process dif- Now member testing looks like: ferent recipes. containsBible = library.has(IsBible()));

2.3.2 Solution Checking for a book with a certain title can be achieved by passing a predicate that receives the The best way to get rid of the above disadvantages book title through its constructor: is to objectify predicates with the Function Object pattern. Combining traversal algorithm and func- library.has(CheckTitle("Moby Dick"))); tion with Function Object works through literally “giving” an objectified function to an internal it- Yet, there is another exciting way to achieve the erator. In our example, the member test method same thing. Although the member test method accepts a test predicate to be used during iteration: expects a predicate with one book parameter only we can make a two argument compare function fit bool has(Function& pred) { by passing a book with the title to be looked for in for (int i=0; i See section 2.9.1 for further details. class Function { Finally, we may combine multiple search criteria public: like title comparison and date checking by compos- virtual Out operator() (In arg)=0; ing predicates with a composite function object: }; library.has(And()(pred1)(pred2)); The ()-operator is defined to take a generic ar- gument type In and to return a generic result type And takes a variable number of predicates as ar- Out. The member test method from above instan- guments, applies each of them to the book it re- tiates these to Book and bool respectively. The ceives, and returns true if all predicates hold. application operator is declared virtual since de- rived Function classes will define concrete func- tions. 2.4 Applicability A predicate to check for a bible instance is: • Parameterization. Function objects are a good candidate whenever general behavior can be class IsBible : public adapted to special behavior: Function { public: Dynamics. In addition to run time selection of virtual bool operator() (Book b) { existing function objects, new function objects return b.type == bible; can also be created at run time. A user may dy- } namically compose a multi-media function ob- }; ject from text-, graphic-, and sound-producing function objects.

3 Orthogonality. Having more than one behav- heavily uses temporary variables for communi- ior parameter creates the problem of handling cation, then the method can be transformed all possible combinations of the individual cases. into a function object. The main transforma- Function objects can freely be mixed without in- tion is to replace the temporary variables with terfering and without combinator classes. function object attributes. As a result, the Reuse. Function objects can be used by any method can be split up into more manageable adaptable algorithm that knows their interface. sub-methods, without passing parameters be- Even if the algorithm was not designed to sup- tween inter-method invocations, since commu- ply a function with necessary arguments, it is nication still can take place via function object often possible to supply them to the function in attributes. The main computation method sim- advance. Consider an error reporter, parameter- ply puts the pieces together, itself being as clear ized by output format functions, only intended as documentation [1]. for generating text messages. We can upgrade • Delayed Calculation. Function objects postpone the reporter to create a graphical alert-box by the calculation of their result until it is actually passing a function object that already received needed. When a function object is passed as information about box-size, colors, etc. a parameter but the receiving method does not Identity. When the behavior of an object should make use of it, it will not be evaluated. If the change while keeping its identity, function ob- result is never needed, this pays off in run time jects can be used as behavior parameters to efficiency. Function Object effectively supports the object. In contrast, encoding behavior in lazy evaluation and thus can be used to imple- subclasses calls for something like Smalltalk’s ment infinite data structures and supports mod- “become:” in order to achieve the same effect. ularization by decoupling data generation from data consumption. • Business transactions. Often the functions are the stable concepts of a system and represent good maintainance spots, in order to cope with Do not use Function unless you have a concrete changing functionality. Instead of being a well- reason. There is a time and space penalty in cre- defined operation on one single object, transac- ating and calling a function object, instead of just tions are “an orchestration of objects working to- invoking a method. Also, there is an initial effort to gether toward a common goal” [4]. When trans- write an extra function class. Functions with many actions do not naturally fit into existing data parameters require as many class definitions in or- abstractions, Function Object can lift them to der to exploit partial parameterization. Finally, first-class status. sometimes unrestricted flexibility as mentioned in section 2.3.1 is clearly desirable. Functions that • Monolithic Algorithms. Just like Strategy [5] vary with the implementation of their argument Function Object can be used to define localized should be members of this abstraction and not free algorithms for data structures. See section 2.13 function objects. Also, see the remarks concerning for a comparison of Command, State, Strategy, flexibility and efficiency in section 2.8. and Function Object. • Small interfaces. When an object potentially 2.5 Structure supports many extrinsic operations (e.g., CAD- objects may support different viewing methods, Client Invoker Function cost calculations, etc.), but its interface prefer- Application(argument) ably should contain the basic, intrinsic functions only (e.g., geometric data), then the functional- ity can be implemented in function objects that take the object as an argument. ConcreteFunction Constructor(initial args) • Method simplification. If a large method, con- Application(argument)

taining many lines of code, can not be split into collected arguments smaller, more simple methods, because the code

4 2.6 Participants • Explicitness. The code cook.prepare(fish) is easy to understand. When recipes are wired • Function into COOK subclasses, cook.prepare depends on the actual cook type. Clever variable names – declares an interface for function application. (e.g., fish cook.prepare) often are not an op- • ConcreteFunction (e.g., isBible) tion, e.g., cook.prepare(fish), followed by cook.prepare(desert). – implements a function. • Compositionality. In analogy to Macro- – collects argument values until evaluation. Command [5], function objects can be dynami- cally composed to form a sequence of functions • Client by forwarding intermediate results to successing function objects. Composite function objects – creates a ConcreteFunction. may also apply several function ob- – possibly applies it to arguments. jects in parallel. Variants differ in the way they – calls Invoker with a ConcreteFunction. produce a final output from the single results. • Uniform invocation. Imposing a function ob- • Invoker (e.g., Iterator) ject’s interface on related operations allows to – applies ConcreteFunction to arguments uniformly invoke them. Instead of switching to different method names (e.g., compTitle, – returns a final result to its Client. compAuthor), we evaluate an abstract function object and rely on dynamic binding [5]. Con- 2.7 Collaborations sequently, we can add new operations, without changing the caller (e.g., event handler). • A client initializes a Function. • Encapsulation. As function objects establish • An invoker takes the Function as a parameter. client relationships only, they are protected from implementation changes to algorithms that use • The invoker applies the Function to arguments. them. Likewise, the implementation of function objects can change without invalidating the al- • The client receives a result from the invoker. gorithms. Hence, Function Object allows black- box reuse and helps to advance reuse by inheri- aClient aFunction anInvoker tance to reuse by composition.

new Function(initial args) Creation • Security. A client of an adaptable algorithm can

InvokerMethod(aFunction) be sure not to change the algorithm semantics. Parameterization It is impossible to be given an optimized ver- Application(arg) Application sion which does not fully comply to the original semantics (see 2.3.1 Unrestricted flexibility). • Flexibility. 2.8 Consequences + A statement like iterator.do(f) is poly- morphic in three ways: • Abstraction. Function objects abstract from 1. iterator may internally reference any function pointers and in particular from point- ers to methods. Instead of the C++ that conforms to a particu- lar interface. code: aFilter.*(aFilter.current)(t), we can write aFilter(t) [4]. 2. The actual instance of iterator deter- mines the iteration strategy (e.g., pre- or • Simplicity. The use of function objects does not post-order traversal on trees). introduce inheritance relationships and does not 3. The actual instance of function object f create spurious combinator classes. determines the iteration function.

5 − It is not possible to automatically optimize etc., elements of all data structures simultane- algorithms for specific functions. Neverthe- ously. less, one more level of indirection can explic- Function Object allows to make iteration a itly construct combinations of functions and method of data structures since it does not de- optimized algorithms. mand for subclassing the data structure. This − When a function has been extracted from a facilitates the use of iterators and allows to data structure, it is no longer possible to sim- redefine iteration algorithms for special data ply redefine it in future derivations. One way structures. Moreover, the data structure (e.g., to account for this is to make the extracted DICTIONARY) then does not need to export meth- function a generic Function Object (see sec- ods (e.g., first, next) in order to allow iterators tion 2.11) that will discriminate between data to access its elements. structure variations. • Efficiency.

• Reuse. Adaptable algorithms become more + A function object may calculate partial re- reusable because they do not need to know sults from arguments and pass these to a re- about additional parameters for functions. sult function. Hence, the partial result is Moreover, function objects are multi-purpose: computed only once, no matter how many times the resulting function object will be + Functions are not bound to a particular applied to different arguments in the fu- adaptable algorithm, e.g., comparing book- ture, e.g., forcesurface = forceearth costly calc, titles is useful for sorting and for membership and then forcemy = forcesurface massmy ; testing in collections. forceyour = forcesurface massyour . + One function with n parameters actually rep- − Passing client parameters to function objects resents n functions and one value. The first can be more inefficient than to, e.g., directly function has n parameters. The second, cre- access internal attributes of an iterator su- ated by applying the first to an argument, perclass. In principle this could be tackled has n − 1 parameters, and so on, until the by compiler optimizations. last function is applied to an argument and − Care should be taken not to unnecessarily produces the result. keep references to unevaluated calculations, An example from physics shows the useful i.e., function objects. Otherwise, the occu- functions which can be created from the grav- pied space can not be reclaimed. itational force function: − Finally, function objects access the public in- m m G m1 m2 terface of their servers only. This represents GravityLaw 1 2 = r2 positive decoupling, but can be more ineffi- forceearth = GravityLaw mass earth cient than unrestricted access. However, se- forcesurface = forceearth radiusearth lective export (Eiffel) or friends (C++), allow forcemy = forcesurface massmy to trade in efficiency for safety. • Iteration. Function Object suggests the use of internal, rather than external, iterators. Inter- 2.9 Implementation nal iterators avoid explicit state and reoccurring • Call-by-value. Function objects must copy their explicit control loops. Often external iterators arguments. Otherwise, their behavior will de- are promoted to be more flexible. It is said to pend on side-effects on their arguments. In gen- be practically impossible to compare two data eral, this will produce unpredictable results. In structures with an internal iterator [5]. How- some cases, however, it may be desirable. The ever, we simply propose to extend an iterator to function object then plays the role of a future accept not just one, but n data structures. A variable, which is passed to an invoker before transfold 1-method may access the first, second, all data needed to compute the result is avail- 1Its functional definition shall be: transfold f a g ≡ able. Long after the function object has been (foldr f a) ◦ (map g) ◦ transpose passed to the invoker, it can be supplied with

6 the necessary data by producing side-effects on ing of function object state can occur. Unfor- arguments. tunately, this forces us to write at least n − 1 classes for a function object with n parameters. • Initial arguments. Real closures (e.g., Smalltalk blocks) implicitly bind variables, which are not 2.9.1 Implementation in C++ declared as parameters, in their creation envi- ronment. This is not possible with function Of the languages discussed in this section, C++ objects. One way out is to treat initial argu- is the only one without garbage collection and ments and standard arguments uniformly: Ini- requires more effort in order to support upward- tial arguments are passed as arguments to the funargs 2 and delayed calculations. Constructors function object in its creation environment. Al- and destructors only work for function objects with ternatively, it is possible to pass initial argu- lifetimes determined by scoping rules. The Bridge ments through the function object constructor pattern [5] can suitably be used to achieve both (see CheckTitle in section 2.3.2). This saves dynamic binding and value semantics with correct the intermediate classes needed to implement memory management [10]. the to initial arguments. Of course, both variants do not exclude each other. 2.9.2 Implementation in Eiffel Note that the implicit variable binding of clo- sures forces them to use the the same variables Eiffel suggests to use the infix operator "@" for names as its creation environment. In contrast, application. In principle, Eiffel allows to use a a function object can be used in various environ- non-generic function interface since the application method can be covariantly redefined. However, we ments without the need to make initial argument ++ names match the environment. recommend to use a generic interface as in C in order to avoid complications through the combina- • Delayed calculation. Commonly a function is tion of polymorphism and covariant redefinition, evaluated after it has received its last argument. i.e., catcalls. Yet, function object application and evaluation can be separated by corresponding methods for 2.9.3 Implementation in Java application and evaluation. As a result, the client, triggering evaluation, does not have to Java neither features covariant redefinition of know about the last argument. Also, the sup- methods nor a genericity mechanism. This means plier of the last argument does not need to en- that we either have many function interfaces, one force the calculation of the result, which is cru- for each , or we must explicitly down- cial for lazy evaluation. In order to enable auto- cast arguments in concrete functions and downcast matic evaluation on full argument supply while results in client code respectively. The latter ap- still supporting the above separation, it is possi- proach is not type safe and is further complicated ble to evaluate on the last parameter and allow a by the fact that basic values must be explicitly kind of dummy parameter (called unit in ML). converted into objects and vice versa. As a mi- nor point, Java does not allow the nice ()-syntax • Partial parameterization. Two extremes to im- of C++. plement partial parameterization exist. The less verbose is to always keep the same instance of 2.9.4 Implementation in Smalltalk function object and assign incoming arguments to corresponding internal attributes. This will Implementation of Function Object is easy and de- cause trouble when the same function object is spite the presence of blocks can still be reasonable: used by several clients. As the application of a Function Object, in addition, allows to reference function object does not create a new instance, functions by (class) name, exploit inheritance be- the clients will get confused at the shared state. tween functions, and to apply ’s method Furthermore, static typing becomes impossible. simplification (see section 2.4). From the exten- If each application of a function object produces sions to Function Object listed in the next section, a new instance of a different type, then static 2Functions returned as results. These do not have a de- typing is enabled again and no unwanted shar- termined lifetime.

7 blocks also do not support keyword parameters and undoing of imperative function objects. virtual bool operator() (Book arg) { return _title == arg.title; 2.10 Sample Code } ++ In combination with the already presented C private: code snippets this section provides a full running string _title; example using a function object to find books in a }; library. First let us define a simple book interface: CheckTitle receives a book during creation and memorizes its title. When applied to a book ar- class Book { gument, the memorized title is compared with the public: book’s title. Book() : title("No Title") {}; Typical client code will declare some books and Book(string t) : title(t) {}; add them to the library: string title; Library library; }; Book book1("The Time Machine"); A collection of such books is maintained in a (in Book book2("2001: A Space Odysee"); this case very simple) library: library.add(book1); class Library { library.add(book2); public: Library() : count(0) {}; class Function& searchTitle=CheckTitle(book1); void add(Book book) { books[count++]=book; cout << "Is book1 in library? " } << library.has(searchTitle) << endl; bool has(Function& pred) { for (int i=0; i

return false; cout << "Is Moby Dick in library? " } << library.has(CheckTitle( Book("Moby Dick"))) private: << endl; int count; The code above demonstrates Book books[10]; }; • how to declare and initialize a function object that is then passed via a variable to the has Class Library allows to add books and it fea- method. tures the has method that we previously encoun- • in-place creation of a function object with its tered. Any predicate pred to be used with has constructor. derives from class Function. Here is the code for predicate CheckTitle: • in-place creation of both function object and its book argument. class CheckTitle : public Function { 2.11 Function Object variants public: CheckTitle(Book book) : This section shortly touches upon important ex- _title(book.title) {} tensions to Function Object.

8 • Keyword Parameters. In addition to stan- patching code is thus distributed over all in- dard application, function objects may pro- volved classes. If, as in the above example, the vide keyword parameters. Accordingly, pa- operation must cope with a symmetric type re- rameters can be passed in any order. This lation (e.g., real+int & int+real), each class makes sense, in order to create useful abstrac- has to know all other argument types. tions. If the definition of the gravitational force in the example of section 2.8 had been A generic3 function object removes the dispatch- m m r G m1 m2 GravityLaw 1 2 = r2 , (note the dif- ing code from the argument types and concen- ferent order of parameters) we can not define: trates it in one place. It uses run time type forcesurface = GravityLaw mass earth radiusearth . identification to select the correct code for a With keyword parameters we can write: given combination of argument types. Note f:=GravityLaw.m1(e-mass).r(e-radius); that nested type switches can be avoided with partial parameterization: Upon receipt of an • Imperative result. It is possible to use the inter- argument, a generic function object uses one nal state of a function object to calculate one or type switch statement to create a correspond- multiple results (add accumulated results to Con- ing new generic function object that will handle creteFunction in the structure diagram of sec- the rest of the arguments. A full application tion 2.5). For instance, one function object may of generic Function Object is presented in [9]. count and simultaneously sum up the integers in Unfortunately, the necessary switch statements a during a single traversal. The set iteration on argument types are sensitive to the introduc- client must request the results from the func- tion of new types4. Yet, in the case of single- tion object through an extended interface (add dispatch simulation, new dispatching methods an arrow getResult from aClient to aFunction in (e.g., add complex) are necessary as well. the diagram of section 2.7). Note that imper- ative function objects may produce any result The goals of the [5] can be from a standard traversal algorithm. The latter achieved with a combination of generic Func- does not need any adaption concerning type or tion Object and any iteration mechanism. A whatsoever. generic function object chooses the appropriate code for each combination of operation and el- • Procedure Object. If we allow function objects ement type. Once the generic Function Object to have side effects on their arguments we arrive has done the dispatch, the exact element type is at the Command pattern extended with param- known and access to the full interface is possi- eters and result value. Procedure Object makes ble. Between invocations, function objects can methods amenable to persistent command log- hold intermediate results, e.g., variable environ- ging, command histories for undoing, network ments for a type-checking algorithm on abstract distribution of commands, etc. Like Command, syntax nodes. Procedure Object may feature an undo method, which uses information in the procedure object’s Note that a generic function object can be real- state to undo operations [5]. Note how easy it ized as a type dispatcher, parameterized with a is to compose a procedure object, to be used as set of function objects that actually perform an an iteration action, with a function object pred- operation. This allows reuse of the dispatching icate that acts as a sentinel for the action. As a part for various operations. result, special iterations as “do if” [12] can be replaced with a standard iteration. Visiting data structures with Function Object • Multi-dispatch. Sometimes an operation de- is acyclic w.r.t. data dependencies [11] and does pends on more than one argument type. For not force the visited classes to know about visi- instance, adding two numbers works differently tors. for various pairs of integers, reals, and complex numbers. Simulating multi-dispatch with stan- 3 Named after CLOS’ generic functions. dard single dispatch results in many additional 4A more flexible approach is to use dynamically ex- methods (like add Integer, add real). The dis- tendible dictionaries that associate types with code.

9 2.12 Known Uses The manages the change of variability autonomously. Function objects Apart from the uncountable uses of Function Ob- are explicitly chosen by the client. Strategies ject in and Scheme, there are chosen by the client also, but indepen- are many truly object-oriented uses: Smalltalk fea- dently of operation requests. tures blocks as true closures with implicit binding ∗ Is it feasible to impose the same interface on of free variables. Sather provides bound routines. all variations? The Eiffel Booch Components uses Function Ob- ject for searching, sorting, transforming and filter- If the available Strategies range from simple ing of containers [6]. The Standard Template Li- to complex, the abstract Strategy must sup- brary, which was adopted as part of the standard port the maximum parameter interface [5]. C++ library, uses Function Object to inline opera- Function Object avoids this by partial param- tions for arithmetic, logic, and comparison [14]. eterization. ∗ Does the combination of common and vari- able part constitute a useful concept? 2.13 Related Patterns The State pattern conceptually represents a 2.13.1 Categorization monolithic finite state machine, so the combi- nation of standard- and state-dependent be- • Objectifier: A function object, like Objectifier, havior makes sense indeed. Strategies are a does not represent a concrete object from the permanent part of general behavior and thus real world [15], though one can reasonably take provide default behavior. Here, the combi- business-transactions for real. Function Object nation acts as a built-in bookkeeping for the is very similar to Objectifier, in that it objectifies selection of the variable part. Function Ob- behavior and takes parameters during initializa- jects take part in the “takes-a” relation. A tion and call. Per contra, clients “have-an” Ob- function object and its receiver are only tem- jectifier, while clients “take-a” function object. porarily combined in order to accomplish a The latter is a uses, not a has-a relationship. task. • Command: A procedure object which does not 2.13.2 Collaboration take any arguments after creation and produces side-effects only boils down to the Command • Iterator: Function objects allow the use of data pattern [5]. One key aspect of Command is from inside (elements) and outside the collec- to decouple an invoker from a target object. tion (previous arguments). There is no collab- Function objects typically do not func- oration between Command and Iterator, since tionality. Rather than delegating behavior to Command does not take arguments. server objects they implement it themselves. • Adapter: Function Object extends the use of So, function objects normally do not work with Parameterized adapters as described in the im- side-effects, but return their computation as an plementation section of the [5] argument-application result. Nevertheless, func- from Smalltalk to any object-oriented language. tion objects also can be used for client/server separation, i.e., as Call-back functions. In ad- • Chain of Responsibility: Pairs of test- (check re- dition to Command, invokers are then able to sponsibility) and action function objects can be pass additional information to function objects put into a Chain of Responsibility in order to by supplying arguments. separate responsibility checks from the execu- tion of tasks. Function Object allows to replace • State/Strategy: Function Object, State [5], and the inheritance relationship between Links and Strategy [5] are concerned with encapsulating Handlers [5] with object-composition. behavior. A decision between them can be based on concerns such as: 2.13.3 Implementation ∗ Who is responsible for changing the variable • Composite: Standard and composed function part of an algorithm? objects can be uniformly accessed with the Com-

10 posite pattern [5]. A composite function for- • accept arguments, which, e.g., enables them to wards arguments to its component functions. A be used for iteration. However, the complete tuple-Composite applies all functions in parallel number of parameters is effectively hidden to to the same argument and thus produces multi- adaptable algorithms, which allows for transpar- ple results. Several reduce functions (e.g., And of ent behavior extensions. section 2.3.2) may somehow fold all results into one output. A -Composite applies each • allow partial parameterization. One function function to the result of its predecessor and thus object definition actually introduces as many forms a calculation pipeline. function objects as the number of its parame- ters. Run time partially parameterized function • Prototype: Often it is useful to distribute the ac- objects can be regarded as dynamically created cumulated state of a function object to different functions. clients. For instance, a a command for delet- • capture data from their creation environment ing text can capture the information whether and previous arguments. Hence, data providers to ask for confirmation or not. However, when can be separated from each other. A function placed on a history list for undoing, different object allows to combine local data from envi- commands must maintain different pointers to ronments, even beyond their lifetime. the deleted text. Consequently, Prototype can be used to clone pre-configured function objects • may dispatch on argument values and/or which should not share their state any further. types. Similar to the State pattern, input- discriminating switches can be distributed to in- • Chain of Responsibility: Generic Function Ob- dividual generic function objects, rather then ject can employ a Chain of Responsibility for being nested at one place. argument type discrimination. Chain members check whether they can handle the actual ar- • can be composed sequentially as well as in paral- gument type. This enables a highly dynamic lel. Sequential composition establishes a calcu- exchange of the dispatch strategy. lation pipeline. Parallel composition calculates tuples of results, e.g., during a traversal.

3 Conclusion • provide local state. Imperative function objects may hold state for algorithms or may accumu- late results during iterations. Hence, function The Function Object (i.e., closure) concept is a objects can compute, e.g., traversal results with- basic design technique that solves many problems. out the need to modify the result type of the This makes its description as a single pattern dif- traversal algorithm. ficult. Nevertheless, we refrained from restricting ourselves to a traditional problem, context, and so- In summary, function objects hide the number of lution triple. We used just one aspect of Function both parameters and results to clients. This can Object for its motivation and supplied illustrating be viewed as an aid to modularization, just like examples for other aspects individually. classes in object-oriented design or higher-order While true closures bind their free variables im- functions and lazy evaluation in functional pro- plicitly, our object-oriented version requires ex- gramming. Accordingly, aggregation (“has-a”), plicit binding. Breuel shows how to still achieve inheritance (“is-a”), and behavior parameteriza- implicit binding by nested class definitions [2]. We tion (“takes-a”) should be equally well-known to have seen, however, that explicit binding does not designers. “Takes-a” realizes object-composition, lose anything essential, but on the contrary decou- as opposed to breaking encapsulation with inheri- ples the function object from its creation context. tance. It is therefore a means of reaching the goal Naturally, Function Object shares many prop- of component oriented software. In combination, erties with Command and Strategy. They abstract inheritance and Function Object allow for flexible from function pointers, support composition, al- prototyping as well as safe black-box composition. low to undo operations, and achieve client/server As well as other patterns, Function Object can decoupling. In addition, function objects: raise the level of design discussions. The term

11 Function Object should immediately communicate Mu¨ller, Dirk Riehle, and Douglas C. Schmidt for the concepts of environment capturing, partial pa- their comments. rameterization, first-class methods, black-box com- position, and so on. Also, the term generic Func- References tion Object is worth being adopted in a designer’s vocabulary. We clearly pointed out the ability of [1] Kent Beck. Method object. Patterns mailing list generic Function Object to lift Iterator to the func- Digest, 96(26), April 1996. tionality of Visitor. [2] Thomas M. Breuel. Lexical closures for C++. In Another advantage of pattern-aided design is C++ Conf. Proc., pages 293–304, October 1988. to work above the level of particular program- [3] Derek Coleman and et al. Object-oriented develop- ming languages. Some patterns, including Func- ment: The Fusion Method. Prentice Hall, 1994. tion Object, even abstract from the implemen- [4] James O. Coplien. Advanced C++: Programming tation paradigm. Indeed, function objects re- Styles and Idioms. Addison-Wesley, 1992. introduce some flavor of structured analysis and [5] E. Gamma, R. Helm, R. Johnson, and J. Vlis- design to object-orientation. This is definitely use- sides. : Elements of Object-Orient- ful. While adding new objects to a system is caught ed Software Architecture. Addison-Wesley, 1994. by an object-oriented decomposition, adding func- [6] Aaron Hillegass. The design of the eiffel booch tionality often is better handled by extending func- components. Eiffel Outlook, 3(3):20–21, December tional abstractions. The control-objects in Jacob- 1993. son’s “use-case driven approach” represent such [7] Robert Hirschfeld. Convenience methods. In The points of functional extendibility. Concerning the 1st Annual European Conference on Pattern Lan- optimal balance between free functions and object- guages of Programming, EuroPLoP ’96, Kloster oriented decomposition, further research is nec- Irsee, Germany, July 1996. essary. Anyway, withstanding the temptation to [8] Thomas Kuhne.¨ Higher order objects in pure implement parameterization with inheritance but object-oriented languages. ACM SIGPLAN No- using function objects means introducing part of tices, 29(7):15–20, July 1994. the functional paradigm into the object-oriented [9] Thomas Kuhne.¨ The translator pattern — exter- paradigm. No longer can we choose one technique nal functionality with homomorphic mappings. In rd from one paradigm only in order to solve a prob- The 23 TOOLS conference USA ’97, St. Bar- lem. We must carefully choose between paradigms bara, California, July 1997. first. While this may appear an extra complica- [10] Konstantin L¨aufer. A framework for higher-order tion to a novice, it is an essential enrichment to functions in C++. In Proc. Conf. Object-Oriented the expert. Technologies (COOTS), Monterey, CA, June 1995. It is well-known that one language’s patterns [11] Robert C. Martin. Acyclic visitor. In Robert C. are the other language’s features. In general, pat- Martin, Dirk Riehle, and Frank Buschmann, ed- terns are thus useful as an indicator of insufficient itors, Pattern Languages of Program Design 3, Reading, Massachusetts, 1997. Addison-Wesley. support. In our point of view, Function Object belongs [12] B. Meyer. Reusable Software. Prentice Hall, 1994. to the category of patterns that any implementa- [13] Dirk Riehle. Bureaucracy — a composite pat- tion language should fully support. In contrast to tern. In Robert C. Martin, Dirk Riehle, and more complex patterns (e.g., Mediator [5] or Bu- Frank Buschmann, editors, Pattern Languages of reaucracy [13]), which are clearly well above im- Program Design 3, Reading, Massachusetts, 1997. Addison-Wesley. plementation level, Function Object works at a ba- sic design level though still supporting higher level [14] A. Stepanov and M. Lee. The standard tem- plate library. ISO Programming Language C++ goals. Project. Doc. No. X3J16/94-0095, WG21/NO482, May 1994. 4 Acknowledgments [15] Walter Zimmer. Relationships between design patterns. In James O. Coplien and Douglas C. Schmidt, editors, Pattern Languages of Program I would like to thank Erich Gamma, Robert Design, pages 345–364. Addison-Wesley, 1994. Hirschfeld, Ralph Johnson, Jiarong Li, Reinhard

12