Better Software - January 2008 - (Page 10) Code Craft Designing Reusable Software by Chuck Allison For software to be reusable, it must be usable in a variety of contexts. An important attribute of reusability at the code level is genericity. Generic software can operate, unmodified, on a variety of object types. Dynamically typed languages provide genericity naturally. Consider the following Python function that determines the smallest of whatever it receives as a parameter: def smallest(stuff): assert len(stuff) > 0 theMin = stuff[0] for x in stuff[1:]: if x >> smallest([1,2,3]) 1 >>> smallest("cba") a The only constraints on the parameter stuff are that it is an iterable entity and that its contained objects support the lessthan operator. Hence, smallest is a generic function. Statically typed languages usually don’t have such flexibility out of the box, but that is changing. Modern languages such as Eiffel, C++, Java, C#, and D have added generic programming capability while retaining the safety and efficiency that comes with static type checking. Consider an everyday programming task: applying a series of transformations to data. Data transformations usually involve calling a series of functions on individual data elements. While it is simple to write separate functions and apply them in sequence, it can be even easier to assemble existing functions into a reusable, composite function. In other words, we want support for function composition. In the November 2007 Code Craft, I used the following Python function: # Listing 1 def compose(*funs): def apply(x): result = x for f in reversed(funs): result = f(result) return result return apply Listing 1 Both functions return a new, single-valued function representing the composition of the functions in the original list. So, if you have three like-typed functions, f, g, and h, you can compose them like this: c = compose(f,g,h) def compose(*funs): return lambda x: reduce(lambda z,f: f(z), reversed(funs), x) Every call to c(x) will compute f(g(h(x))). How can we accomplish this in C++? It won’t be a one-liner, but there is a reasonable solution. But first, let’s start with a nongeneric version and then generalize it. A Non-Generic Example In case you forgot, reduce applies its first argument, a binary function that I’ll call the applicator, to the first list element along with the initial value. That result and the next function in the list become input arguments to a second invocation of the applicator, and so on, until the list of functions is exhausted and the accumulated result is obtained. If you prefer a procedural rendering of compose, see listing 1. 10 We’ll assume the data type is double and will use C++’s accumulate algorithm, which works just like Python’s reduce. Since we can’t return functions in C++, we’ll create a function object (a type implementing operator()), as shown in listing 2. With a vector, v, of single-valued real functions, using their composition is straightforward: BETTER SOFTWARE JANUARY/FEBRUARY 2008 www.StickyMinds.com ISTOCKPHOTO You can call this function with any type of sequence: http://www.StickyMinds.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.