RR: Avoiding Artificial Class Hierarchies

Polymorphism is a cornerstone of object oriented programing. It allows run-time resolution of the class function (method) to be called, depending on concrete type of the object. This is of course extremely useful, but requirement for run-time resolution of function called should not be by itself the reason for deciding on a deep and complex class hierarchy. If run-time resolution is all that is required, then much simpler solutions based on function pointers, or boost::function object are much better suited.

Example Here is a very simplified example from financial engineering of how one could easily get into complex hierarchies: class Opt { public : /// Returns true if a barrier has been hit virtual bool barrier ( double S ) = 0 ; /// Returns payoff at maturity for underlying price S virtual double pay ( double S ) = 0 ; }; I.e., a simple abstract virtual class that defines two functions, barrier and pay . To define a concrete class you need to override the two pure virtual definitions with appropriate definitions. Again a very simple example of a concrete class: class Vanilla : public Opt { /// Strike double K ; public : bool barrier ( double S ) { return false ; } double pay ( double S ) { return ( S - K ) > 0 ? S - K : 0 ; } };

Problem The above classes work fine, and in this particular example may be the best way to describe the problem. But, let us see what the potential problems with this approach are. Imagine you wish to maximise code re-use and minimise the type of copy-and-paste programming that sometimes blights large project. Also imagine there is a number of types of Opt that have no barrier, i.e., barrier should always return false . To prevent code duplication, it is nice to solve explicitly through inheritance: class NoBarrier : public Opt { public : bool barrier ( double S ) { return false ; } }; class Vanilla2 : public NoBarrier { /// Strike double K ; public : double pay ( double S ) { return ( S - K ) > 0 ? S - K : 0 ; } }; But thinking along the same, there are also a number of sub-types of Opt that have the pay of the type that Vanilla has. One would then do: class PlainPay : public Opt { /// Strike double K ; public : double pay ( double S ) { return ( S - K ) > 0 ? S - K : 0 ; } }; class Vanilla3 : public NoBarrier , public PlainPay { }; This resolves the code duplication issues, but at a cost of having a fairly complex class inheritance hierarchy. In this problem this may be optimal solution, but sometimes what is required is something that is simpler.

Alternative There are two basic requirements which lead to the hierarchy above: We wished to keep two functions together that weren't necessarily closely related (in this example barrier and pay )

and ) We wanted to minimise code duplication and maximise testability If this is really all that is required, that it can be implemented directly very simply and without a complex class hierarchy: #include <boost/function.hpp> #include <boost/bind.hpp> struct Opt { /// Returns true if a barrier has been hit boost :: function < bool ( double x ) > barrier ; /// Returns payoff at maturity for underlying price S boost :: function < double ( double x ) > pay ; }; bool noBarrier ( double S ) { return false ; } double plainPay ( double S , double K ) { return ( S - K ) > 0 ? S - K : 0 ; } /// Return a plain vanilla option Opt Vanilla ( double K ) { Opt o ; o . barrier = noBarrier ; o . pay = boost :: bind ( plainPay , _1 , K ); return o ; } Explanation The basic requirement that we want to keep two functions together is easily implemented as a structure of two function objects. In many ways this is making explicit what the virtual function mechanism in C++ does behind the scenes. The implementation: struct Opt { /// Returns true if a barrier has been hit boost :: function < bool ( double x ) > barrier ; /// Returns payoff at maturity for underlying price S boost :: function < double ( double x ) > pay ; }; is based on boost::function objects rather than plain pointer because of the extra flexibility they provide (see boost manual page for more details). The run time resolution of which function to call is extremely explicit, in that at any point in the program the value of barrier or pay members can be assigned a different function or object. Next up are the definitions of the pay off and barrier functions. Because they can now be free functions, the are extremely simple and self contained. Finally, there is a function that which creates an object with equivalent functionality to the example we had at the start: /// Return a plain vanilla option Opt Vanilla ( double K ) { Opt o ; o . barrier = noBarrier ; o . pay = boost :: bind ( plainPay , _1 , K ); return o ; } Clearly this approach allows easy mix and match of functions to use for the barrier and pay members. In this example, I made use of the boost::bind function to avoid having to write the trivial class which just holds the value K (c.f. PlainPay above). Note that _1 is the placeholder for the parameter which is left free by the bind function.