<<

. 8
( 9)



>>

i++)
{
theArray[i] =
cells(row+3+i,column);
cells(row+3+i,column).clear();
}

add(thisName,theArray);

rowsDown = maxi(rowsDown,size+2);

column+=1;
}
else
{
std::string value =
cellBelow.StringValueLowerCase();
add(thisName,value);
column++;
cellBelow=empty;
}
}
}
}
}
row+=rowsDown+1;
232 Templatizing the factory

}

{for (unsigned long i=0; i < rows; i++)
for (unsigned long j=0; j < columns; j++)
if (!cells(i,j).IsEmpty())
{
GenerateThrow("extraneous data "+ErrorId,i,j);
}}
}
The constructor takes the name for the structure the string in the top left corner
of the CellMatrix. In the event, that this is not a string, it throws. It also throws
if the rest of the line is non-empty.
Throughout, every time a cell is used, its value is set to empty. This means that,
at the end, we can check that every value has been used simply by checking that
all cells are empty; if one is not, we throw. We also check to ensure that no error
values have been passed in, and return an error message if they have.
We then scan through each row looking for identi¬er tags. If we ¬nd a string,
then we look for data below it. Either there is data immediately below, or there is
a tag specifying type of data: “cells, list, matrix, array, vector.” The types “vector”
and “array” both specify an “array.” If there is a tag, we look below again for the di-
mension of the data, and then extract out the table of data using the ExtractCells
function.
Note that if the argument is of type “list”, we convert it to an ArgumentList and
then discard the result. This allows us to be sure that no errors will be generated by
the conversion to an ArgumentList at a later stage when the object is queried for
this argument.
If there is no tag, then the argument is a number, boolean or string and we iden-
tify the type from the CellValue and add it to the ArgumentList.
Whenever an error is found, we call the GenerateThrow method which attaches
the row and column of the problem to the error message to make it easier for the
user to spot the problem.


14.9 The template factory
We have seen how to code an argument list class and how to create objects of the
class from a spreadsheet input. This solves the factory problem of having to cope
with many types of arguments, since we just encapsulate them all in the new class.
We are now in a position to develop the template factory advertised at the start of
the chapter.
Here is the factory from xlw
14.9 The template factory 233

Listing 14.4 (ArgListFactory.h)

#ifndef ARG_LIST_FACTORY_H
#define ARG_LIST_FACTORY_H
#ifdef _MSC_VER
#if _MSC_VER < 1250
#pragma warning(disable:4786)
#define VC6
#endif
#endif

#include <xlw/ArgList.h>
#include <map>
#include <string>

template<class T>
class ArgListFactory;

// friend rather than method to avoid bug in VC6.0
// with static data in member template functions
template<class T>
ArgListFactory<T>& FactoryInstance()
{
static ArgListFactory<T> object;
return object;
}

template<typename T>
class ArgListFactory
{
public:
#ifndef VC6
friend ArgListFactory<T>& FactoryInstance<>();
#else
friend ArgListFactory<T>& FactoryInstance();
#endif
typedef T* (*CreateTFunction)(const ArgumentList& );
void RegisterClass(std::string ClassId, CreateTFunction);
T* CreateT(ArgumentList args);
˜ArgListFactory(){};
234 Templatizing the factory

private:
std::map<std::string, CreateTFunction> TheCreatorFunctions;
std::string KnownTypes;
ArgListFactory(){}
ArgListFactory(const ArgListFactory&){}
ArgListFactory& operator=(
const ArgListFactory&){ return *this;}
};

template<typename T>
void ArgListFactory<T>::RegisterClass(std::string ClassId,
CreateTFunction CreatorFunction)
{
MakeLowerCase(ClassId);
TheCreatorFunctions.insert(
std::pair<std::string,
CreateTFunction>(ClassId,CreatorFunction));
KnownTypes+=" "+ClassId;
}

template<typename T>
T* ArgListFactory<T>::CreateT(ArgumentList args)
{

std::string Id = args.GetStringArgumentValue("name");

if (TheCreatorFunctions.find(Id) ==
TheCreatorFunctions.end())
{
throw(Id+" is an unknown class. Known types are"
+KnownTypes);
}

return (TheCreatorFunctions.find(Id)->second)(args);
}


// easy access function
template<class T>
T* GetFromFactory(const ArgumentList& args)
14.9 The template factory 235

{
return FactoryInstance<T>().CreateT(args);
}
#endif
The factory is templatized on a type T, which, is the type of the base class. After
studying how to do generic singletons at the start of the chapter, you will note
that this is not how the factory has been done. The reason is that the curiously
recurring template pattern singleton is too smart for some compilers (e.g. VC6.0);
when optimizing they get confused about how many copies there are of a static
variable declared in a method of a template class.
Instead, we therefore work with a friend function called FactoryInstance
which can access the private constructor. This has a static variable of type
ArgListFactory<T>, and so plays the same role as the static member function
Instance in our previous factory. Note the syntax for the friend declaration:
#ifndef VC6
friend ArgListFactory<T>& FactoryInstance<>();
#else
friend ArgListFactory<T>& FactoryInstance();
#endif
In up-to-date compilers, we have to include <> at the end of the method name.
The rest of the template class is very similar to our non-template factory. Note
that we make the names lower case to avoid confusion, and we store a list of all
names registered to make it easy to guide the user when an invalid name is passed
in. The CreateT method only takes in an ArgumentList and does not take in
a separate key; instead the key is queried from the ArgumentList with the tag
“name.”
We include the extra function
T* GetFromFactory(const ArgumentList& args)
to make calling the factory particularly easy.
We also need the helper class to register classes inherited from T with the factory.
This is done in the ¬le xlw/ArgListFactoryHelper.h
#ifndef ARG_LIST_FACTORY_HELPER_H
#define ARG_LIST_FACTORY_HELPER_H
#include <xlw/ArgListFactory.h>
#include <string>

template<class TBase, class TDerived>
236 Templatizing the factory

class FactoryHelper
{
public:
FactoryHelper(std::string);
static TBase* create(const ArgumentList&);
˜FactoryHelper(){}
};


template<class TBase, class TDerived>
FactoryHelper<TBase,TDerived>::FactoryHelper(std::string id)
{
MakeLowerCase(id);
FactoryInstance<TBase >().RegisterClass(id,
FactoryHelper<TBase,
TDerived>::create);
}


template<class TBase, class TDerived>
TBase*
FactoryHelper<TBase,TDerived>::create(
const ArgumentList& Input)
{
return new TDerived(Input);
}

#endif



Here everything has been templatized on both the base class and the derived class.
The derived class will be the class being registered and the base class will specify
the factory to be registered with. Otherwise, our helper class is very much the same
as the non-template one.
Note that we have written our class to only work with the ArgumentList; we
could go further and templatize on the argument type, then having two template pa-
rameters for the factory and three for the helper class. However, the ArgumentList
class is suf¬ciently general that the extra ¬‚exibility would seem to gain us little at
the cost of opaque syntax.
14.10 Using the templatized factory 237

14.10 Using the templatized factory
We have now achieved our objective; we have a general template factory, which
will take in multiple arguments. We return to our original motivating example:
coding a factory for a pay-off class that takes in multiple arguments. An example
of this is given in the “TestFiles” folder in xlw.
The PayOff class there is very simple

Listing 14.5 (PayOff.h)
#ifndef PAYOFF_H
#define PAYOFF_H
class PayOff
{
public:

PayOff();
virtual double operator()(double Spot) const=0;
virtual ˜PayOff();
virtual PayOff* clone() const=0;

private:

};
#endif
The trivial implementations of the constructor and destructor are in PayOff.cpp.
Inherited from this class, we have three examples given in PayOffConcrete.cpp.

Listing 14.6 (PayOffConcrete.h)
#ifndef PAYOFF_CONCRETE_H
#define PAYOFF_CONCRETE_H

#include "PayOff.h"
#include <xlw/ArgList.h>
#include <xlw/Wrapper.h>
#include <xlw/ArgListFactory.h>

class PayOffCall : public PayOff
{
public:
238 Templatizing the factory

PayOffCall(ArgumentList args);
virtual double operator()(double Spot) const;
virtual ˜PayOffCall(){}
virtual PayOff* clone() const;

private:
double Strike;

};


class PayOffPut : public PayOff
{
public:

PayOffPut(ArgumentList args);
virtual double operator()(double Spot) const;
virtual ˜PayOffPut(){}
virtual PayOff* clone() const;

private:
double Strike;

};


class PayOffSpread : public PayOff
{
public:

PayOffSpread(ArgumentList args);
virtual double operator()(double Spot) const;
virtual ˜PayOffSpread(){}
virtual PayOff* clone() const;

private:
Wrapper<PayOff> OptionOne;
Wrapper<PayOff> OptionTwo;
double Volume1;
double Volume2;
14.10 Using the templatized factory 239

};


#endif

We have classes for the put, the call, and a spread, which is a linear multiple of
two other pay-offs. In all three cases, the sole constructor takes an ArgumentList,
so the factory is directly usable. The class PayOffSpread can be viewed as an
example of the composite pattern, which is similar to decorator; the difference
being that more than one underlying class is involved.
The classes are implemented in PayOffConcrete.cpp.

Listing 14.7 (PayOffConcrete.cpp)

#include <xlw/port.h>
#include "PayOffConcrete.h"

PayOffCall::PayOffCall(ArgumentList args)
{
if (args.GetStructureName() != "payoff")
// must be lower case here throw("payoff structure expected
in PayOffCall class");

if (args.GetStringArgumentValue("name") != "call")
throw("payoff list not for call passed to PayOffCall"
" : got "+args.GetStringArgumentValue("name"));

Strike = args.GetDoubleArgumentValue("strike");
args.CheckAllUsed("PayOffCall");
}

double PayOffCall::operator () (double Spot) const
{
return Spot-Strike > 0.0 ? Spot-Strike :0.0;
}

PayOff* PayOffCall::clone() const
{
return new PayOffCall(*this);
}
double PayOffPut::operator () (double Spot) const
240 Templatizing the factory

{
return Strike-Spot > 0.0 ? Strike-Spot :0.0;
}

PayOffPut::PayOffPut(ArgumentList args)
{
if (args.GetStructureName() != "payoff")
// must be lower case here throw("payoff structure expected"
"in PayOffCall class");

if (args.GetStringArgumentValue("name") != "put")
throw("payoff list not for put passed to PayOffPut : got "
+args.GetStringArgumentValue("name"));

Strike = args.GetDoubleArgumentValue("strike");
args.CheckAllUsed("PayOffPut");
}

PayOff* PayOffPut::clone() const
{
return new PayOffPut(*this);
}


double PayOffSpread::operator()(double Spot) const
{
return Volume1*(*OptionOne)(Spot)+
Volume2*(*OptionTwo)(Spot);
}
PayOffSpread::PayOffSpread(ArgumentList args)
{
if (args.GetStructureName() != "payoff")
// must be lower case here throw("payoff structure expected"
"in PayOffCall class");

if (args.GetStringArgumentValue("name") != "spread")
throw("payoff list not for spread passed to"
"payoffspread : got"+args.GetStringArgumentValue(
"name"));
14.10 Using the templatized factory 241

if (!args.GetIfPresent("Volume1",Volume1))
Volume1= 1.0;

if (!args.GetIfPresent("Volume2",Volume2))
Volume2= -1.0;

OptionOne = Wrapper<PayOff>(GetFromFactory<PayOff>(
args.GetArgumentListArgumentValue(
"optionone")));

OptionTwo = Wrapper<PayOff>(GetFromFactory<PayOff>(
args.GetArgumentListArgumentValue(
"optiontwo")));

args.CheckAllUsed("PayOffSpread");
}

PayOff* PayOffSpread::clone() const
{
return new PayOffSpread(*this);
}

The implementation of these classes are straightforward, with the only interest
being in how the ArgumentList class is used. For the PayOffPut class, we ¬rst
check that the ArgumentList class has been tagged with “payoff.” Note that all
data passed in have been put into lower case so we must use lower case when
checking. We then check that the name argument is indeed “put.” In each case, we
throw if there is a problem.
We get the strike by calling GetDoubleArgumentValue("strike") and put it
into the relevant data member. Finally, we make sure that the user has not supplied
extra irrelevant arguments using the CheckAllUsed method.
The constructor for PayOffSpread is more interesting. The ¬rst part is the same
as before. We then check to see if the notionals of the two underlying options have
been speci¬ed and otherwise set default values.
To get the underlying options themselves, we use list arguments from the
ArgumentList passed in and call the same factory. Note that the factory returns
raw pointers, but these are immediately taken over by the Wrapper class, which
ensures that they are properly memory managed.
Note the important synergies here between the composite pattern and the
ArgumentList class. We are able to bring our composite into the factory because
242 Templatizing the factory

it is legitimate to have data stored in the ArgumentList class, which is of the same
type, and can therefore be used to create more objects from the factory. Note that
we could even specify the inner class to be another PayOffSpread. The process
has to end somewhere, since the number of cells used to make each successive
CellMatrix gets smaller each time.
We still have to register these classes with the factory, this is done in
PayOffRegistration.cpp

Listing 14.8 (PayOffRegistration.cpp)
#include <xlw/ArgListFactoryHelper.h>
#include "PayOffConcrete.h"

namespace
{
FactoryHelper<PayOff,PayOffCall> callHelper("call");
FactoryHelper<PayOff,PayOffPut> putHelper("put");
FactoryHelper<PayOff,PayOffSpread> spreadHelper("spread");
}
Why do this is in a separate ¬le? The reason is that if we decide to place the PayOff
classes in a static library, then we cannot put the registrations in the library. The
reason is that if we do, then they will be ignored! Material in a static library is only
included when linking if it is referenced somewhere; a global variable declaration
not mentioned anywhere will not be referenced and so not included.


14.11 Key points
In this chapter, we have seen how to create a templatized factory and met a few
techniques along the way.
• Private inheritance can be used to express “implemented in terms of.”
• The curiously recurring template pattern can be used to make the return type of
a base class method equal to the type of the inherited class.
• The singleton can be implemented using the curiously recurring template pattern.
• We can use an argument list class to encapsulate a variable number of arguments
of varying types.
• Some compilers have problems with the curiously recurring template pattern
implementation of the singleton.
• The argument list class allows us to create a templatized factory without worry-
ing about the types of arguments.
• The CellMatrix class gives us a way of transferring data to and from spread-
sheets without having to deal with the particulars of the spreadsheet™s data types.
14.12 Exercises 243

14.12 Exercises

Exercise 14.1 Modify the random number classes to work with the ArgumentList
factory. Include anti-thetic sampling and moment matching with arbitrary underly-
ing classes amongst the classes to register.

Exercise 14.2 Modify the xlw factory so it uses the Singleton class developed
here.

Exercise 14.3 Create a static library containing the pay-off classes from xlw and
check how the registration works.
15

Interfacing with EXCEL




15.1 Introduction
The xlw package consists of a set of routines for building xlls. An xll is a dynamic
link library (dll) that contains some special functions that allow the user to register
functions with EXCEL. Once the xll has been created we simply open it from
EXCEL, and some new functions appear that can be used just like ordinary inbuilt
functions.
Our focus in this chapter is on how to use xlw. We do not address how it works.
Indeed the philosophy of the current version is that using it should be similar to
using a compiler “ we wish to understand how to use all the features, but not how
it works internally. The source code is fully available for those who are curious,
however.
In this chapter, we will restrict our discussion to xlw 2.1. The package can be
obtain from xlw.sourceforge.net. There is also an xlw-users mailing list
which you can subscribe to for further discussion. The essential difference between
the series 2 releases of xlw, which the author of this book wrote, and previous
releases due to Jerome Lecomte and Ferdinando Ametrano is that the interfacing
code is written automatically, so the user needs to know nothing about special data
types or registration code.
The package comes with project ¬les for 4 four different IDES: Visual Studio
6.0, 7.1, and 8.0, and for DevCpp. The DevCpp IDE is an open source IDE, which
uses the MingW g++ compiler, so in particular this allows production of xlls using
that compiler.
The xlw 2.1 package comes in three pieces:
• a console application run from the command line called InterfaceGenerator;
• a static library called xlwLib;
• and an example project with the name varying with compiler.
The user ¬rst has to build the InterfaceGenerator and xlwLib. Interfacing is

244
15.2 Usage 245

done by applying InterfaceGenerator to header ¬les at the command line. This
then produces a C++ source ¬le, which contains the code to interface the functions
declared in that header ¬le to EXCEL. A project then has to be built that links
against xlwLib and includes the new source ¬le.
The main trickinesses in the use of xlw are to do with how to set up projects and
build for the ¬rst time; no actual interface coding is done by the user.


15.2 Usage
Before using xlw 2.1, we ¬rst have to build the xlw 2.1 library and the interface
generator. The interface generator project can be found in the directory appropriate
for your compiler:
• For DevCpp look in the folder xlwDevCpp, and the project is called
InterfaceGenerator.dev.
• For Visual Studio 8.0, open the solution in the folder xlwVisio8, and the project
is called InterfaceGenerator.
• For Visual Studio 7.1, open the solution in the folder xlwVisio7, and the project
is called InterfaceGenerator.
• For Visual Studio 6.0, open the workspace in the folder xlwVisio6, and the
project is called InterfaceGenerator.
This project should be built and will produce a console application called
InterfaceGenerator.exe. Note that we can use the version of this application built
with any one compiler with any other compiler without trouble.
Second we need to build the xlw 2.1 library to link against. The project ¬les are
in the same place as for the console application.
• For DevCpp the project ¬le is called DevCppLibXl.dev, and the library ¬le is
called DevCppLibXl.a, and is built in to the same folder.
• For Visual Studio 8.0, the project is called xlwLib. The built libraries are
xlwLib-Debug.lib and xlwLib.lib, and will be built into xlwLib/Release and
xlwLib/Debug, respectively.
• For Visual Studio 7.1, the project is called xlwLib. The built libraries are
xlwLib-Debug.lib and xlwLib.lib, and will be built into xlwLib7/Release and
xlwLib7/Debug, respectively.
• For Visual Studio 6.0, the project is called xlwLib. The built libraries are
xlwLib-Debug.lib and xlwLib.lib, and will be built into xlwLib6/Release and
xlwLib6/Debug, respectively.
For each compiler, an example project is given of functions to be exported to the
xll. These are called: DevCppXll.dev and xlwVisio. Each project contains a header
246 Interfacing with EXCEL

¬le Test.h, a source ¬le Test.cpp and an interface ¬le xlwTest.cpp; these are
contained in the folder TestFiles. Some ¬les for payoffs can also be found there,
and example spreadsheets.
It is the interface ¬le xlwTest.cpp that has been automatically generated. To
re-generate it, simply ensure that InterfaceGenerator.exe is in the path or in the
same directory as Test.h and then at a command prompt type “InterfaceGenerator
Test.h.”
Simply building the xll project will then produce an xll, which can be opened in
EXCEL and produces extra functions in a library called “MyTestLibrary.”
To use xlw 2.1 for your own functions, you must ¬rst write a C++ function
which compiles and builds except for the interfacing code. The functions to be ex-
ported to EXCEL should be contained in header ¬les which contain nothing else.
The InterfaceGenerator should then be applied to them. If the header ¬le is called
MyFile.h, the new ¬le will be called xlwMyFile.cpp. The new ¬le should then
be added to the project. Note InterfaceGenerator will ignore any preprocessor com-
mands, and will throw an error if the header ¬le contains any classes or function
de¬nitions. It will also protest if any unknown data types are found; we discuss
what data types are acceptable in Section 15.3.
The information for the function wizard in EXCEL is taken from comments and
the names of argument variables in the header ¬le. This means that arguments must
be named. A comment should follow each argument name and this will appear in
the function wizard when that argument is being entered. The general description
of the function should be in a comment between the type of the function and its
name.
Arguments can be passed by reference or by value, and can be const or non-
const. (In fact, these have no effect on the coding of the interface ¬le.)
Once the interface ¬le has been added to the project, we simply build the project
and then the output xll ¬le should be openable by EXCEL. Note that we can have
any number of interface ¬les in the same xll project.
If you wish to create a new xll project, this can be done. The things to do are:

• The folder containing the xlw folder must be on the include path.
• The folder containing the xlw library ¬le must be on the linking path.
• The xlw library ¬le must be on the list of ¬les to link against (i.e. for Visual
studio, xlwLib.lib in release mode and xlwLib-Debug.lib in debug mode).
• The project must be a dll project in DevCpp. (Create a dll project, remove the
¬le created by DevCpp, and then add your ¬les.)
• The project must use multi-threaded dll code generation in Visual Studio. This
means that you should create a dll project, or create a “Win32” application and
then use “Application settings” to switch its type to a dll.
15.3 Basic data types 247

• Change the name of the output ¬le to MyName.xll.

Note if you are working with Visual Studio 8.0 Express, in addition, you must
do the following:

• Install the Microsoft Platform SDK; this can be downloaded from the Microsoft
website.
• The include directory for the SDK must be on the include path; this should hap-
pen automatically when you install the SDK.
• Link against the following libraries in debug mode: odbc32.lib odbccp32.lib,
User32.lib, xlwLib-Debug.lib.
• Link against the following libraries in release mode: odbc32.lib, odbccp32.lib,
User32.lib, xlwlib.lib
• Make sure the SDK library directory is included on the list of directories to
search for library directories.
• When creating a new project, you must use create new project from existing
code, and then later on say that it is a dll project. (This is not an option when
creating new projects from new code.)



15.3 Basic data types
The function to be exported to EXCEL can only use data types supported by the in-
terface generator. These are divisible into basic data types and extended types. The
basic types are double, short, NEMatrix, MyMatrix, MyArray, CellMatrix,
string, std::string, and bool. The extended data types are: int, unsigned
long, ArgumentList, DoubleOrNothing, and PayOff.
The reason that int and unsigned long are extended types rather than basic
types is that the type used by xlw to communicate with EXCEL is the XLOPER.
This is a polymorphic data type with two numeric data types that are essentially
short and double, so other numeric types go via double.
The class MyMatrix is de¬ned via a typedef in MyContainers.h to MJMatrix.
You can change this to your favourite matrix type. The matrix class must support
the following: it should have .rows() and .columns() de¬ned, a constructor
that takes number of rows and columns, and elements should be accessible via
a[i][j]. If your matrix class only supports element access via round brackets,
you should de¬ne the macro USE PARENTHESESES.
The class NEMatrix is a typedef for MyMatrix, but if you declare an argument
to be of this type, then the function will not be called unless the argument is a non-
empty matrix of numbers. (Otherwise, you get #VALUE.) If you are working with
very large matrices, it should be more stable as the data type is much simpler and
248 Interfacing with EXCEL

uses a different mechanism for transmitting the data to and from EXCEL. (For xll
experts, it uses type “K” rather than type “P.”)
The class MyArray is also de¬ned via a typedef in MyContainers.h. The de-
fault is to typedef to std::vector. It must have .size(), a constructor taking
the size, and operator[] de¬ned.
We discussed the CellMatrix class at length in Section 14.8. The fact that this
class allows a table of cells of arbitrary values including errors means that the
conversion of EXCEL data to it should virtually never fail, since it allows error
codes.
The types std::string and string are both allowed. These are the same class
and the difference is simply in whether the namespace std has already been de-
clared via using.


15.4 Extended data types
The xlw 2.1 package has been designed to make it easy to work with your own data
types. The only constraint is that a function (or method) must exist that takes in a
data type that is already constructible from basic types and creates the new type. We
require the construction to be from a single previous type: argument speci¬cation
would get rather complicated if multiple types were allowed. For this purpose, a
constructor is equivalent to a function.
To add in extra types, we have to modify the InterfaceGenerator project. We
simply add a declaration in the ¬le TypeRegistrations.cpp. Note that the new
classes themselves should not be included in the InterfaceGenerator project,
since this project™s role is to write C++ code and not to create executables.
For example
TypeRegistry::Helper
arglistreg("ArgumentList", // new type
"CellMatrix", // old type
"ArgumentList", // converter name
false, // is a method
true, // takes identifier
"", // no key
"<xlw/ArgList.h>" // force inclusion
// of this file
);

TypeRegistry::Helper
payoffreg("Wrapper<PayOff>", // new type
"ArgumentList", // old type
15.4 Extended data types 249

"GetFromFactory<PayOff>",
// converter name
false, // is a method
false, // takes identifier
"" , // no key
"<xlw/ArgListFactory.h>"
);
The ¬rst argument is the identi¬er for the new type.
The type to convert from is speci¬ed by the second argument.
The third is the function or method used to construct the new type from the old
one.
The ¬rst bool is to specify whether the conversion function is a method of the
old class, or simply a function or constructor that takes in an object of the old class.
The second bool indicates whether the converter method or function takes in a
second argument that is a string expressing an identi¬er in case of error “ this is
very handy when trying to work out which argument in your complicated function
is dubious.
For the curious only, the key is to tell EXCEL the type, this is generally only
used when de¬ning a basic type. This is typically “R” or “P.” Doubles are passed
as type “B” and non-empty matrices as “K.” The types “R” and “P” indicate that the
data are passed using the very useful but slightly painful data type XLOPER, which
xlw then turns into an XlfOper. The type “K” means to pass using a ¬‚oating point
array, and “B” means pass directly as a double.
The last argument allows the forcing of extra #includes in our .cpp interface
¬le. This allows us to ensure that the conversion function is available.
We can de¬ne new types from other new types. The maximum depth is 26, at
which point the parser concludes that we have accidentally created a loop.
The three main data types that have been added for illustration are the
DoubleOrNothing, ArgumentList and Wrapper<PayOff>. The ArgumentList
we discussed at length in Chapter 14.
The DoubleOrNothing class allows us distinguish between a number passed in
or an empty argument. We can therefore choose between a number passed in, and
a default value if the argument is empty.
We illustrate using an argument list factory with EXCEL using the PayOff class.
The factory returns a raw pointer to the base class, so this should be immediately
converted to a smart pointer as we discussed in Section 13.3. Our new data type is
therefore
Wrapper< PayOff >
which takes ownership and ensures deletion at the appropriate time. Note the point
250 Interfacing with EXCEL

here that although the factory returns a raw pointer, the registration simply speci¬es
the Wrapper, which silently takes ownership of the pointer.
We discuss brie¬‚y how this is implemented in the InterfaceGenerator project.
The mechanism here is similar to that used for the factory. Every declaration of
a TypeRegistry::Helper registers the new type with the IncludeRegistry
class. This class is implemented using a singleton de¬ned via the curiously recur-
ring template pattern from Section 14.2.


15.5 xlw commands
When we look for your new functions in the function wizard in EXCEL, we will
¬nd that there is a new set of commands called “MyTestFile”: the default name of
the library in EXCEL is the name of the header ¬le. We can change this by inserting
the line
//<xlw:libraryname=MyTestLibrary
in the header ¬le. Note that all functions in the header ¬le will have the same library
name, which will be that speci¬ed by the last libraryname command.
Some functions in EXCEL have the property of giving a different value each
time they are called; for example, the time or the RAND() function. These functions
are said to be volatile. If we want a volatile function, then this can be done
as follows
double // system clock
//<xlw:volatile
SystemTime(DoubleOrNothing ticksPerSecond
// number to divide by
);
We can also time functions by inserting
//<xlw:time
in the same place. This causes two cells to be added below the function™s re-
sults containing “time taken” and the time taken in seconds. It is possible to time
volatile functions; the order of the two commands is not important.


15.6 The interface ¬le
The interface generator creates the ¬le xlwMyTestFile.cpp; it is not necessary
to ever look at this interface ¬le. However, it can be edited directly if so desired.
It ¬rst has a DummyFunction declared in an unnamed namespace. This function
15.6 The interface ¬le 251

references the functions xlAutoOpen and xlAutoClose and thus forces their in-
clusion in the xll. These functions carry out the registration of the other functions
with EXCEL and are therefore essential.
There is a line

const char* LibraryName = "MyTestLibrary";

This speci¬es the name of the library in the EXCEL function wizard. This is en-
closed in an anonymous namespace, so we can have multiple interface ¬les in the
same xll.
For each function, there are two parts. The ¬rst is the registration informa-
tion. The second is the wrapper function called between EXCEL and the function
chosen.
An example of the registration information is

namespace
{
XLRegistration::Arg
ConcatArgs[]=
{
{ "str1"," first string "},
{ "str2","second string "}
};

XLRegistration::XLFunctionRegistrationHelper
registerConcat("xlConcat",
"Concat",
" Concatenates two strings ",
LibraryName,
ConcatArgs,
"RR");
}

The code is placed in an unknown namespace to ensure it does not affect any
linkage. The arguments are declared in the ¬rst part, with the name of each fol-
lowed by its description.
In the second part, a global variable is declared. The creation of this global vari-
able registers the function with a global singleton, which ensures that it is registered
with EXCEL. This approach allows the registration to be split across many ¬les.
The information passed to the constructor is the name of the function in C++ in
the interface ¬le, the name of the function in EXCEL, the function description, the
252 Interfacing with EXCEL

name of the library in EXCEL, the arguments declared above, and the types of the
arguments. The types are expressed via a code, e.g.:

• R “ LPXLOPER by reference
• P “ LPXLOPER by value
• B “ double
• K “ ¬‚oating point array

In xlw 2.1, only the types P, B, K, and R are used. P is used for CellMatrix
and MyMatrix. K is used for NEMatrix. B for double. R is used for all other basic
types. Types such as bool are therefore ¬rst passed in as LPXLOPERs and then
transformed into the right data type.
An example of the interface function de¬nition is

extern "C"
{
LPXLOPER EXCEL_EXPORT
xlConcat(
LPXLOPER xlstr1_,
LPXLOPER xlstr2_)
{
EXCEL_BEGIN;

if (XlfEXCEL::Instance().IsCalledByFuncWiz())
return XlfOper(true);

XlfOper xlstr1(xlstr1_);
std::string str1(xlstr1.AsString("str1"));

XlfOper xlstr2(xlstr2_);
std::string str2(xlstr2.AsString("str2"));

std::string result(
Concat(
str1,
str2)
);
return XlfOper(result);
EXCEL_END
}
}
15.7 The interface generator 253

The extern ˜C™ command is necessary as we are using the C API and therefore
must use C linkage.
The return type of the function is always LPXLOPER, but since this is a polymor-
phic data type, this is not a hindrance. EXCEL EXPORT is a macro

#define EXCEL_EXPORT __declspec(dllexport)

This ensures that the function is a dll export, and so can be dynamically linked
against.
Note that types are passed in as LPXLOPERs not XlfOpers or other types.
XlfOpers are not used since they cause a crash with the MinGW compiler as they
are not POD (plain old data) objects.
The macros EXCEL BEGIN and EXCEL END contain starting and ¬nishing infor-
mation common to all functions. In particular, EXCEL END contains catches for
common data types to return information to EXCEL.
The routine then checks if it is being called from the function wizard. If it is,
then it immediately returns to EXCEL. This avoids time-consuming computations
being called whilst data are being entered.
Each argument is then converted. First to an XlfOper, and then using the .As
methods to the correct type. Note a string is passed into the .As method, this
allows a throw to identify the offending argument. If you use extended types, there
will be a string of conversions here.
Once the arguments have been converted, the original function is called and the
result stored. For return to EXCEL, it is converted into an XlfOper and this is
returned as an LPXLOPER.



15.7 The interface generator
The interface generator is written as a simple C++ routine. It is a console applica-
tion that takes in one argument. The output ¬le name is an optional argument and
it defaults to adding “xlw” on the front and “.cpp” at the end.
The routine ¬rst reads in the ¬le and places it in a vector of chars for conve-
nience. It is then turned into tokens. Each token will be an identi¬er, preprocessor
directive, comment, or delimiter.
Tokens corresponding to consts and ampersands are then removed, since they
will not affect the coding of the interface routine. At this stage, unsigned identi¬ers
are also dealt with.
Once this has been done, the ¬le is turned into a list of functions, with each
function having a list of arguments with names and types.
The next operation is to identify all the types and ¬nd the conversion routines.
254 Interfacing with EXCEL

Once this has been done, the output ¬le is written into a vector, and then written
to a ¬le.


15.8 Troubleshooting
If you ¬nd that you can build the xll but that the functions do not register, here are
some common problems with xlls in general.
If absolutely nothing happens, then check security settings for macros. The de-
fault setting is to ignore ¬les containing macros. Note for a reasonable level of
security setting, you will get asked whether to enable macros; if this does not hap-
pen then security levels are too high or possibly too low.
If you get an error saying that the ¬le is in an “unrecognizable format,” possibil-
ities are
• Missing dlls on your machine. This often occurs if you compile in VC7 on one
machine and then move the xll to another one. This can be cured either by work-
ing out how to get the compiler not to need the dlls, or by copying the required
dlls to the new machine (or switch to using DevCpp.) Another solution is to
download “Microsoft Visual C++ 2005 Redistributable Package (x86)” which
is designed to solve this sort of problem but needs to be installed on the new
machine.
• Failure to export the auto open and auto close functions.
The dumpbin utility can be used to check whether the right functions are being
exported. If you have followed the instructions here, this should not be an issue.


15.9 Debugging with xlls
Suppose you have managed to build and run the xll. Now you want to debug it. It
is still possible to use the Visual Studio debugger. Here are the precise instructions
for Visual C++ 8.0. The approach is similar for the other Visual Studios. DevCpp
does have an inbuilt debugger, GDB, but it seems painful to use it.
• In the project properties, go to the “Debugging” part of the “Con¬guration” prop-
erties . In the “Command” entry select “Browse” and then browse for the EXCEL
executable.
• Below this, look for “command arguments.” In here we want the xll. To get this
go to the “Linker” part of “Con¬guration” properties and look for the value of
“output ¬le.” Copy this and paste it into “command arguments.”
• Hit the F5 key.
The debugger should now stop on breakpoints in your C++ code, as usual, when
your functions are used.
15.11 Exercises 255

You can now exit in two ways: either by using the “stop debugging” command
in the “debug” menu, or by exiting EXCEL in the ordinary way. The ¬rst method
causes EXCEL to think that it crashed, and it will ask you about ¬le recovery on
next being run. It is therefore best avoided.


15.10 Key points
• Quants generally don™t use console applications.
• xlls are a standard way of interfacing with EXCEL.
• xlw gives an easy way to create xlls.
• All interfacing code is generated automatically by xlw.


15.11 Exercises

Exercise 15.1 Download and build xlw.

Exercise 15.2 Create an xll that prices a Black“Scholes option using the analytic
formula from the appendix.

Exercise 15.3 Set up a new xlw project.

Exercise 15.4 Modify the InterfaceGenerator project so that it interfaces random
number generators.
16

Decoupling




16.1 Introduction
Have you ever worked on a library that you were scared to rebuild because it would
take too long? Or have you been afraid to change the contents of a ¬le because of
the knock-on effects making everything recompile? Have you ever included a ¬le in
your project and discovered that this made you include a large number of seemingly
irrelevant ¬les in your project to get rid of unresolved symbol linker errors?
We have focussed in this book on issues relating to logical design and code
reuse. These examples are, however, not problems with logical design; for example,
adding an extra data member to a class forces every client to recompile but will not
cause any of them to have compilation errors. All these are examples of physical
design problems. Encapsulation, which we have discussed and illustrated at length,
assists with logical design but not physical design.
Physical design problems indicate pieces of code that are more tightly coupled
than they should be. In this chapter, we study physical design practice, and, in
particular, examine the concept of insulation. This is a much stronger requirement
than encapsulation, the difference being that if class A is insulated from class B, then
changes to A do not cause B to recompile. Whereas encapsulation merely guaran-
tees that B will not have to be recoded.


16.2 Header ¬les
The fundamental difference between header ¬les and source ¬les is that header
¬les are included by other ¬les both header and source via #include, whereas
source ¬les should not be. The ¬rst consequence of this is that every time you use
#include in a header ¬le, you are including a ¬le not just into that header ¬le but
also into every ¬le that includes it both directly and indirectly.
Unnecessary header ¬le inclusions therefore slow compile times in two ways,
¬rst by causing the compiler to look at much more code for each compiled source
¬le, and second by causing more source ¬les to require compilations. How can we
reduce the numbers of #includes?

256
16.2 Header ¬les 257

The ¬rst and most important method is simply by being aware of the issue. If
you are ever tempted to #include a ¬le just because your client might need it,
don™t! If your client needs it, he will include it for himself.
A second method which can make a large difference is to use forward declara-
tions. Often in a header ¬le we simply need to know that a class exists, we don™t
need to know anything more about it. For example, suppose we have declared a
function f in our header ¬le that takes in a CellMatrix and returns a double. We
could code this in two ways

Listing 16.1 (ExampleFile1.h)
#ifndef EXAMPLE_FILE1_H
#define EXAMPLE_FILE1_H

#include "CellMatrix.h"

double f(const CellMatrix& cells);

#endif


or by

Listing 16.2 (ExampleFile2.h)
#ifndef EXAMPLE_FILE2_H
#define EXAMPLE_FILE2_H

class CellMatrix;

double f(const CellMatrix& cells);

#endif
The ¬rst method forces any ¬le that includes ExampleFile1.h to recompile
every time a change is made to CellMatrix.h or to a ¬le included by it. The
second does not. Here is a non-trivial example of this technique taken from xlw:
#ifndef DOUBLE_OR_NOTHING_H
#define DOUBLE_OR_NOTHING_H
class CellMatrix;
#include <xlw/port.h>
#include <string>
258 Decoupling

class DoubleOrNothing
{
public:
DoubleOrNothing(const CellMatrix& cells,
const std::string& identifier);

bool IsEmpty() const;
double GetValueOrDefault(double defaultValue) const;

private:
bool Empty;
double Value;

};

#endif

The DoubleOrNothing class uses the CellMatrix in its constructor only so it
does not have to include the ¬le from its header ¬le. Of course, the source ¬le does
include it

Listing 16.3 (DoubleOrNothing.cpp)

#include "DoubleOrNothing.h"
#include "CellMatrix.h"

DoubleOrNothing::DoubleOrNothing(const CellMatrix& cells,
const std::string& identifier)
{
if (cells.ColumnsInStructure() != 1
|| cells.RowsInStructure() != 1)
throw("Multiple values given "
"where one expected for DoubleOrNothing "
+identifier);


if (!cells(0,0).IsEmpty() && !cells(0,0).IsANumber() )
throw("expected a double or nothing, got something else "
+identifier);

Empty = cells(0,0).IsEmpty();
16.3 Splitting ¬les 259


Value = Empty ? 0.0 : cells(0,0).NumericValue();

}

bool DoubleOrNothing::IsEmpty() const
{
return Empty;
}

double DoubleOrNothing::GetValueOrDefault(double defaultValue)
const
{
return Empty ? defaultValue : Value;
}
If you get the error “unde¬ned class” when compiling, this means that you have for-
ward declared a class but not included it when it is really needed. Note that clients
passed a DoubleOrNothing generally will not need to include CellMatrix.h,
since this is only needed for the constructor.
When can we use this technique? As long as we have no variables of the type of
the class, and we attempt to call no methods of the class, then a forward declaration
is suf¬cient. This means that if we have data members of type CellMatrix, then
we must include CellMatrix.h, but we can have pointers of type CellMatrix* if
we wish without inclusion. We can also use forward-declared classes as arguments
of functions and as return types.
One thing we cannot do is forward declare identi¬ers that are typedefed. So if
we have de¬ned MyArray by typedef, then we must always include the ¬le with
the typedef. Note the unpleasant consequence of this is that if we have forward
declared our array class everywhere and then decide that we want to switch to an-
other class, then we will get compilation errors everywhere if we decide to achieve
the change via typedef.


16.3 Splitting ¬les
An important physical design issue is how to divide up code. The simplest form of
this question is “how many classes do I put in one ¬le?” An easy answer is one. The
only problem with this is that you will ¬nd that you very quickly have hundreds of
¬les, which you may or may not ¬nd annoying.
An important rule to follow is that abstract base classes should have their own
¬les. Most clients will only ever need to see the declaration of the base class, since
260 Decoupling

they will work with references to the base class or (smart) pointers to base class
objects. Since most base classes have no data members, this can mean no implied
inclusions.
This effect is multiplied when we use factories “ in that case, even the ¬le that
instantiates the object of type X never needs to include the class declaration of
X, and, in fact, it never even needs to know that X exists. For an example of this
approach, see the ¬les PayOff.h and PayOffConcrete.h in the xlw project. The
inherited class, which are concrete rather than abstract, are in PayOffConcrete.h,
but PayOff.h is almost empty but it is all that clients need to see

Listing 16.4 (PayOff.h)

#ifndef PAYOFF_H
#define PAYOFF_H
class PayOff
{
public:

PayOff();

virtual double operator()(double Spot) const=0;
virtual ˜PayOff();
virtual PayOff* clone() const=0;

private:

};
#endif

In addition, the ¬les Test.h and Test.cpp, which use the PayOff classes, never
include PayOffConcrete.h. Try this: make a small change to PayOffConcrete.h,
and hit build; the only ¬les that recompile are PayOffConcrete.cpp and
PayOffRegistration.cpp.
A secondary rule worth following is to split ¬les when classes require quite
different inclusions. The inclusions required give a good indicator of similarity
and they are the aspect of the class that has the biggest knock-on effect.


16.4 Direction of information ¬‚ow and levelization
When implementing two related classes X and Y, we need to think about what we
really need to know about the other. For example, consider the issue of interfac-
ing with EXCEL. We want to be able to input matrices of type MyMatrix from
16.4 Direction of information ¬‚ow and levelization 261

EXCEL; we also want to be able to return them to EXCEL via the XlfOper data
type.
How can we implement this functionality? There are a number of solutions:
(i) Give MyMatrix a constructor that takes in an XlfOper and a method
.AsXlfOper() that turns it into an XlfOper.
(ii) Give XlfOper a constructor that takes in a MyMatrix and a method
.AsMatrix() that converts back.
(iii) Do both (i) and (ii).
(iv) Write functions
MyMatrix ConvertToMatrix( const XlfOper& inputOper);
XlfOper ConvertToXlfOper(const MyMatrix& inputMatrix);
and put them in a ¬le on their own.
If we adopt solution (i), then every time we use the MyMatrix class we must in-
clude the XlfOper class and everything that XlfOper requires; this is true in both
compile and link senses. However, we can create matrices and convert them to
XlfOpers with little coding. Whereas if we adopt solution (ii), then we have the
opposite dependency, and conversion back and forwards is still easy to write.
Solution (iii) means that we have dependencies both ways, and choices on how
to do the conversion. Choice is not necessarily good, since it always raises the
question of which way to do it.
Solution (iv) creates no dependencies between the two classes. We can use matri-
ces without worrying about EXCEL interfacing and vice versa. The main downside
is that it is a little clunky syntactically.
In order to decide which is best, we need to consider what direction information
¬‚ows in, and what dependencies we are happy with. Solution (i) means all our
numerical code is dependent on our EXCEL interfacing code. If we decide that we
want to use a different spreadsheet package, we are stuck with including the xlw
¬les. This is clearly a bad idea; this rules out solutions (i) and consequently (iii) as
well.
Solution (ii) has the opposite dependency: the xlw code has to know about the
matrix class. This is not so bad, since if we change the matrix class, we will still
want to be able to interface the new class with EXCEL; changing the matrix class
will force recompilation of some of the xlw ¬les but not have other drastic effects.
It is very unlikely that we will ever want to get rid of matrices altogether.
We have already ruled out solution (iii), but we discuss the consequences a little
further. Suppose we had gone down this route. This would mean that it was im-
possible to use the matrix class without the EXCEL interfacing code, and it would
be impossible to use the EXCEL interfacing code without the matrix class. At that
point, we might as well put them in the same ¬le, since each one requires the other.
262 Decoupling

Solution (iv) is nice in that we have fully decoupled the two classes; we simply
have an extra ¬le that depends on both of them. On the other hand, the syntax is a
little non-obvious, and we will spend a certain amount of time having to look it up
each time we do the conversion.
The xlw package uses solution (ii) on the grounds that the extra decoupling does
not buy us anything in this particular case and, given the natural dependencies
between classes, the additional dependency is not an issue. Note that the entire
package does this for all conversions.
In general, think about which direction information ¬‚ows naturally, and whether
you really want users of class X to be forced to deal with Y and vice versa. If in
doubt, use solution (iv), since this gives the maximum amount of decoupling.
Another way to think about this is in terms of fundamental types: a type should
only depend on types that are more fundamental than it. So in xlw, the PayOff
classes depend on ArgumentLists, which depend on the CellMatrix class but
not the other way round. This means that we should avoid solution (iii) as much as
possible. If it seems that two classes are at a similar level of fundamentalism, then
you should probably be using solution (iv).
This leads to the idea of levelization. We assign a level number to each class; the
more fundamental a class is, the lower its level is. A class or ¬le should only depend
on classes and ¬les that are on strictly lower levels. We should therefore never have
a pair of classes that both depend on each other, either directly or indirectly.


16.5 Classes as insulators
Consider the CellMatrix class, this was introduced to insulate EXCEL from the
numerical code. It encapsulates the notion of an input table of cells from any
spreadsheet. It can therefore carry any information that can be input from a spread-
sheet, which can then be converted into any class as desired via argument lists.
However, the CellMatrix class itself does not depend in any way on the code
for interfacing with EXCEL. It therefore acts as a messenger between EXCEL and
the numerical code without creating dependencies: both the numerical code and
the EXCEL code depend on CellMatrix, but it depends on neither.
In fact, the CellMatrix class depends only on basic container classes and the
standard library. We can therefore view it as being on a very low level. Note the
general technique here: we can achieve decoupling by using a low-level class to
communicate between disparate pieces of code.


16.6 inlining
The keyword inline is often used for optimization. What does it do? It gives the
compiler the option of replacing a function call with the actual code de¬ning the
16.7 Template code 263

function. This eliminates a function call, thus saving a little time. In addition, the
fact that the code is being considered at the same time as the surrounding code
allows an optimizing compiler to make additional optimizations.
A typical use for inline is for data access operations. For example, when de¬n-
ing an array class, it is common to make operator[] an inline method. Thus
encapsulation of private data is preserved with no speed cost at run-time.
The ¬rst point to be aware of is that the inline only gives the compiler an
option; it can be happily ignore the suggestion if it wants to.
A second more important point is that whilst we have preserved encapsulation
at no run-time cost, we have lost a lot of insulation at plenty of compile- and link-
time cost. For inline to work, the function must be provided in the header ¬le;
thus we now have dependency on the implementation of the function or method. If
we change the function™s implementation, all clients must recompile. With a non-
inline function de¬ned in the source ¬le, the impact would be minimal. Note also
that de¬ning a function in a header ¬le may also require extra #includes, creating
further dependencies.
Another aspect of inlining to consider is that if the function is non-trivial and
heavily used, there will be a lot of copies of the function sprinkled throughout the
code, which will increase executable size.
In conclusion, whilst inlining is useful for avoiding performance overheads with
private data, be aware of the downsides and do not overuse it.


16.7 Template code
The standard way to work with template code is to ¬rst declare the template class
or function in a header ¬le, and then in the same header ¬le provide the method or
function de¬nitions.
We therefore have no insulation between the class and its clients. Any change
to any aspect of a template class will force recompilation of all its clients. This
is quite different from non-template code, where changing the implementation of
functions and methods has no compile-time effects on clients.
The gains and losses of template code are really very similar to those with
inline. We gain on run-time speed and reusability, but lose on compile time.
The reader is probably wondering why template code has to be done this way.
Why can™t we have template code de¬ned in a source ¬le? The answer is that we
can, but that most modern compilers are not yet up to it. The keyword for doing this
is export and only one compiler, the Comeau compiler, currently supports it. It is
suf¬ciently controversial that there were motions to remove it from the next C++
standard; however, these were defeated so export will remain in the standard at
least, for a while.
264 Decoupling

16.8 Functional interfaces
When we discussed the conversion between matrices and XlfOpers, one solution
was to simply use two functions contained in a separate ¬le. This can be viewed
as a functional interface approach to decoupling. By introducing functions in a
third ¬le we can convert between disparate objects without them knowing anything
about each other.
Another example of functional interface decoupling is the EXCEL C API. Com-
municating via a simple functional gateway with C linkage allows both sides of the
gate to change dramatically without forcing changes on the other side. If we build
an xll for one version of EXCEL and then up-grade to a new version, then the xll
will still work. Similarly, EXCEL knows nothing about the interiors of our xlls.
The key here is that two quite different components have had their method of
communication restricted to occur in a quite precise way. As long as this remains
true, the two pieces can vary without knock-on effects.


16.9 Pimpls
In this section, I want to brie¬‚y mention an idiom that I do not use personally;
however, it represents the ideas in this chapter pushed as far as they will go, so the
reader should be aware of it.
The essential difference between encapsulation and insulation is that when we
change the private section of the class then we do not affect classes that are
protected by encapsulation, but we do fail the insulation test because all client
classes have to recompile.
If we could move all the private section into the source ¬le, then this problem
would disappear. The PIMPL idiom is one way to achieve this. PIMPL stands for
“Private Implementation.” The essence of the approach is to have the class that is
visible to clients, A, contain no data except a pointer to an unde¬ned class, B, which
is de¬ned in the source ¬le. In addition, we place B in an unnamed namespace so
it has internal linkage and can have no compile- or link-time effects on other ¬les.
It is B that contains all the data, so when we change the class data members there
is no knock-on effects. We have thus achieved perfect insulation.
What are the consequences of this approach? The ¬rst point to note is that the
data member of A is a pointer, so all memory allocation has to be dynamic; that
is, we must use new to create objects of type B and then manage their copying
and destruction as well. Whilst the coding pain can be minimized by using an
appropriate smart pointer, it is still some extra ¬ddliness.
We also have the issue that new is slow. This means that we really do not want
to do this when speed is important. This not a huge issue in that it is rarely wise
to create and destroy objects of any non-trivial class in the core part of numerical
16.11 Exercises 265

routines where all the time is taken, in any case; this criticism equally applies to
any class that has a container as a data member.
There is also a memory cost; we need an extra pointer for each object from the
class. This is not a real problem; if you are using many objects from this class and
the size of a pointer is noticeable, you should probably not be using this idiom for
other reasons such as speed.
The main downside for me with PIMPL is that the additional clunkiness out-
weighs the gains in insulation. It is therefore not a great idea for numerical coding.
However, if you ever need to work on a large system that has heavy amounts of non-
numerical code, it is worth considering. See [32] for an enthusiastic exposition of
the technique, and also for some discussion of how to avoid the time consumption
issues with memory allocation.


16.10 Key points
In this chapter, we have examined how to reduce, compile, and link dependencies
using the concept of insulation.
• Physical design relates to how ¬les depend on each other.
• Encapsulation stops us from having to rewrite code.
• Insulation saves us from having to recompile code.
• Being careful with #include can speed up compile times.
• Levelization yields a natural way to eliminate excess dependencies.
• Inlining has costs in terms of physical design as well as gains in terms of run
speed.
• Template code increases coupling.
• PIMPL is a powerful methodology for minimizing dependencies.
This chapter has been greatly in¬‚uenced by Lakos™s book, Large Scale C++
Software Design, [16]. Whilst it is now a little dated, there is still a wealth of useful
discussion and techniques. Sutter™s “Exceptional” books, [32, 33, 34] also discuss
similar issues at length, but are more recent.


16.11 Exercises

Exercise 16.1 Take the most recent project you have completed and time a “rebuild
all.” Now see how many #includes you can eliminate via forward declaration and
time again. Repeat after splitting out abstract base classes.

Exercise 16.2 Implement a class using the PIMPL idiom.
Appendix A

Black“Scholes formulas




<<

. 8
( 9)



>>