Hi, I'm trying to get my head around using policy based design in C++ using templates; it seems that quantlib uses this approach a lot. My basic question involves trying to figure out under what circumstances templates should be utilized in certain design features (with regard to policy based design - not so much with regards to generic container classes etc.) As an example, imagine I was going to create a Bond class; I might do it as follows:
class Bond : public Security { protected: PrinicipalSchedule principalSchedule; CouponSchedule couponSchedule; TerminationProvision terminationProvision; DefaultGuarantee defaultProvision; public: //various useful methods go here }
The basic idea is to abstract away certain things to provide enough flexibility to deal with issues like callabillity, amortizations, bizarre payment dates, whatever. Of course classes like TerminationProvision would have to be carefully crafted in order to handle the wide variety in which bonds can cease to exist. This class would be used by various pricing engine objects to perform calculations. But in any case I would think that my approach is more or less what someone with a Java background would attempt - with the understanding that occasionally some situations might require using 'instanceof'.
My question then is: in c++ is the above approach optimal or is there some more powerful paradigm that would utilize templated classes?
Or more relevant to quantlib: Can someone elaborate on why SwaptionPricer is templated:
template<class ModelType> class SwaptionPricer : public PricingEngine, public Patterns::Observer, public Patterns::Observable
as opposed to something like
class SwaptionPricer : public PricingEngine, public Patterns::Observer, public Patterns::Observable {
Handle<SwaptionModel> model_;
}
class SwaptionModel { SwaptionResults calcSwaption(SwaptionParameters parameters); }
Thanks, Nehal |
This kind of template design for pricer (see after ==>) is less preferred in a trading system because in cases where multiple models are available for the same instrument, the trading system typically allows users to configure their model choice and let them switch around. This dynamic behavior vs the static polymorphism nature of template is mind twisting. But quantlib may have other concerns that led to its current pricer design. -Lou, Wujiang -Zurich Capital Markets
==> Or more relevant to quantlib: Can someone elaborate on why SwaptionPricer is templated:
template<class ModelType> class SwaptionPricer : public PricingEngine, public Patterns::Observer, public Patterns::Observable
This email and any attachments are confidential and may be legally privileged. No confidentiality or privilege is waived or lost by any transmission in error. If you are not the intended recipient you are hereby notified that any use, printing, copying or disclosure is strictly prohibited. Please delete this email and any attachments, without printing, copying, forwarding or saving them and notify the sender immediately by reply e-mail. Zurich Capital Markets and its affiliates reserve the right to monitor all e-mail communications through its networks. Unless otherwise stated, any pricing information in this e-mail is indicative only, is subject to change and does not constitute an offer to enter into any transaction at such price and any terms in relation to any proposed transaction are indicative only and subject to express final confirmation. |
In reply to this post by Nehal Patel
Hi all,
sorry, I don't have much time for answering at lenght---it will have to wait a few days. However: At 09:14 AM 7/14/03 -0400, Lou, Wujiang wrote: >This kind of template design for pricer (see after ==>) is less preferred >in a trading system because in cases where multiple models are available >for the same instrument, the trading system typically allows users to >configure their model choice and let them switch around. This dynamic >behavior vs the static polymorphism nature of template is mind twisting. run-time polymorphism is not prevented by the current design. In general, compile-time and run-time polymorphism do not exclude each other--they can be mixed, as in: class Model { public: virtual void foo() = 0; }; class SomeInstrument { public: double calculate(Model* m); }; template <class Policy1, class Policy2=SomeDefault> class Foo : public Model { public: void foo() { /* whatever, using the chosen policies */ } }; Model* modelFactory(int tag) { switch (tag) { case 1: return new Foo<SomePolicy>; case 2: return new Foo<SomeOtherPolicy>; case 3: return new Foo<SomeOtherPolicy,NotTheDefault>; default: return NULL; } } int main() { std::cout << "Choose a model:" << std::endl; std::cout << "[1]: vanilla-flavored" << std::endl; std::cout << "[2]: peppermint-flavored" << std::endl; std::cout << "[3]: caffeinated" << std::endl; Model* model; int tag; std::cin >> tag; model = modelFactory(tag); while (model == NULL) { std::cout << "Wrong choice, try again" << std::endl; std::cin >> tag; model = modelFactory(tag); } SomeInstrument i; std::cout << "Your result is " << i.calculate(model) << std::endl; delete model; return 0; } et voila', run-time polymorphism! (of course in a real trading system the factory would be called behind a configuration window with checkboxes and stuff, and it would be passed more arguments based on which the correct model is to be chosen.) Later, Luigi P.S. Also, you can easily turn compile-time polymorphism into run-time polymorphism by means of a polymorphic proxy class, but you can't do the opposite... |
In reply to this post by Nehal Patel
Thanks for the post(s). For whatever reason I have yet to get a good grasp
on the benefits of compile time polymorphism/templates -- that is: how does one identify which situations are good for applying templates (again ignoring the standard examples of containers or generic algorithms or smart pointers)? At this point, the major benefits seem to be: 1) Ability to avoid certain runtime, type check errors 2)Ability to produce optimized code in certain situations (for instance you can get away with inline expansion in some cases for which normal runtime polymorphism would have lead to an indirection + real function call). I guess at the end of the day, templates provide a way of providing optimized code without sacrificing too much of the design? The tradeoff is that it is not easy to document the "required" interface for a class template parameter(but of course the compiler will quickly tell you if you try to use a class with an incomplete interface for a given template -- but of course the error message will be book-lengthed and utterly unintelligible :) Anyway I guess I am looking for a killer example of some templated policy design that would have been difficult to achieve using an inner class member variable with a fixed interface. Cheers, nehal -----Original Message----- From: Luigi Ballabio [mailto:[hidden email]] Sent: Monday, July 14, 2003 11:34 AM To: [hidden email] Subject: RE: [Quantlib-users] Policy-Based Design/Templates/Quantlib Hi all, sorry, I don't have much time for answering at lenght---it will have to wait a few days. However: At 09:14 AM 7/14/03 -0400, Lou, Wujiang wrote: >This kind of template design for pricer (see after ==>) is less preferred >in a trading system because in cases where multiple models are available >for the same instrument, the trading system typically allows users to >configure their model choice and let them switch around. This dynamic >behavior vs the static polymorphism nature of template is mind twisting. run-time polymorphism is not prevented by the current design. In general, compile-time and run-time polymorphism do not exclude each other--they can be mixed, as in: class Model { public: virtual void foo() = 0; }; class SomeInstrument { public: double calculate(Model* m); }; template <class Policy1, class Policy2=SomeDefault> class Foo : public Model { public: void foo() { /* whatever, using the chosen policies */ } }; Model* modelFactory(int tag) { switch (tag) { case 1: return new Foo<SomePolicy>; case 2: return new Foo<SomeOtherPolicy>; case 3: return new Foo<SomeOtherPolicy,NotTheDefault>; default: return NULL; } } int main() { std::cout << "Choose a model:" << std::endl; std::cout << "[1]: vanilla-flavored" << std::endl; std::cout << "[2]: peppermint-flavored" << std::endl; std::cout << "[3]: caffeinated" << std::endl; Model* model; int tag; std::cin >> tag; model = modelFactory(tag); while (model == NULL) { std::cout << "Wrong choice, try again" << std::endl; std::cin >> tag; model = modelFactory(tag); } SomeInstrument i; std::cout << "Your result is " << i.calculate(model) << std::endl; delete model; return 0; } et voila', run-time polymorphism! (of course in a real trading system the factory would be called behind a configuration window with checkboxes and stuff, and it would be passed more arguments based on which the correct model is to be chosen.) Later, Luigi P.S. Also, you can easily turn compile-time polymorphism into run-time polymorphism by means of a polymorphic proxy class, but you can't do the opposite... ------------------------------------------------------- This SF.Net email sponsored by: Parasoft Error proof Web apps, automate testing & more. Download & eval WebKing and get a free book. www.parasoft.com/bulletproofapps1 _______________________________________________ Quantlib-users mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/quantlib-users |
At 01:19 PM 7/14/03 -0400, Nehal Patel wrote:
>Thanks for the post(s). For whatever reason I have yet to get a good grasp >on the benefits of compile time polymorphism/templates -- that is: how does >one identify which situations are good for applying templates (again >ignoring the standard examples of containers or generic algorithms or smart >pointers)? As a very, very rough rule of thumb, I'd use run-time polymorphism for interfaces and compile-time polymorphism for implementations. Something like: class Engine { public: virtual void calculate() const = 0; }; template <typename T, class Policy> class SomeEngine : public Engine { public: void calculate() const; }; but I'm sure there are very obvious counter-examples to the above. I mostly go by gut-feeling myself... >At this point, the major benefits seem to be: 1) Ability to >avoid certain runtime, type check errors True, and it can go way further than you would expect: for an application we won't be using in QuantLib, see http://oonumerics.org/tmpw01/brown.pdf where templates are used for (brace yourself) compile-time dimensional analysis of physical formulas... >2)Ability to produce optimized code in certain situations (for instance >you can get away with inline expansion in some cases for which normal >runtime polymorphism would have lead to an indirection + real function call). Also, compilers often cannot do their fancy optimizations around virtual calls. And adding up inlining and optimization you can save quite a few cycles, as you just found out for the BermudanSwaption example... >I guess at the end of the day, templates provide a way of providing >optimized code without sacrificing too much of the design? Yes. Also, 3) with run-time polymorphism you can have virtual methods, but not "virtual types", while templates allow you to use traits---see e.g. http://www.moderncppdesign.com/publications/traits.html > The tradeoff is that it is not easy to document the "required" > interface for a class template parameter (but of course the compiler will > quickly tell you if you try to use a class with an incomplete interface > for a given template -- but of course the error message will be > book-lengthed and utterly unintelligible :) I agree---the required interface should be documented. >Anyway I guess I am looking for a killer example of some templated policy >design that would have been difficult to achieve using an inner class >member variable with a fixed interface. Hmm, I don't really know about killer apps... for a survey of template programming and its use for efficient calculations, you can have a look at http://osl.iu.edu/~tveldhui/papers/techniques/techniques.ps For examples of what is possible to do with templates, see Todd Veldhuizen's papers at http://osl.iu.edu/~tveldhui/papers/ and Andrei Alexandrescu's at http://www.moderncppdesign.com/publications/ Later, Luigi |
Hello,
Before taking on Basket options I thought I'd port the Barrier option code to the PricingEngine framework, and then attempt Monte Carlo for Barriers. I need some guidance on the separation of concerns of the different directories. I think that it would be cleanest if all enum declarations (for OptionType, BarrierType, CapFloor::Type) were in the same location. It would also make sense if we had a pattern for the declarations for Arguments and Results, currently some are in with the Instruments, and some are in with the PricingEngines. I suggest that the Instruments have 'ownership' of their Arguments and Results, as there may be many Engines for each Instrument (I realise it is actually a many-to-many relationship). This would mean, for example, moving the VanillaOptionArguments from vanillaengines.hpp to vanillaoption.hpp. There should then be no references to specific PricingEngines in the Instruments. Any suggestions / objections / comments? Thanks, Neil --------------------------------------------------- Neil Firth Brasenose College Oxford OX1 4AJ United Kingdom Office: 01865 280616 [hidden email] http://www.maths.ox.ac.uk/~firth --------------------------------------------------- |
In reply to this post by Luigi Ballabio-2
Hi Neil,
At 03:57 PM 9/4/03 +0100, Neil P Firth wrote: >I need some guidance on the separation of concerns of the different >directories. I think that it would be cleanest if all enum declarations >(for OptionType, BarrierType, CapFloor::Type) were in the same location. Hmm, except for the fact that e.g., Option::Type lives inside Option and CapFloor::Type inside CapFloor... there's hope, but I don't think I'm tackling this right now. >It would also make sense if we had a pattern for the declarations for >Arguments and Results, currently some are in with the Instruments, and >some are in with the PricingEngines. > >I suggest that the Instruments have 'ownership' of their Arguments and >Results, as there may be many Engines for each Instrument (I realise it is >actually a many-to-many relationship). This would mean, for example, >moving the VanillaOptionArguments from vanillaengines.hpp to >vanillaoption.hpp. There should then be no references to specific >PricingEngines in the Instruments. Yes, I second that. Incidentally, this also goes towards moving the engine machinery up to the Instrument class (right now it's in Option only.) I guess I'll have to see whether there's some way to abstract the instrument/arguments/result/engine thing so that it's easier to declare... Later, Luigi |
Free forum by Nabble | Edit this page |