
2011/3/10 Chad Nelson <chad.thecomfychair@gmail.com>:
On Wed, 9 Mar 2011 19:11:31 +0100 Joachim Faulhaber <afojgo@googlemail.com> wrote:
This is my review on the XInt library. [...]
Thank you for the review, and the comments.
Thank you for your replies and questions [...]
2.3 Policy based design =======================
I think policy based design is a very good and powerful technique that is specifically useful to separate implementation variants of class templates in clear and flexible ways. Unfortunately I can not see that you are actually using policy based design here. Because your design lacks typical policy classes that encapsulate implementation variants in a way that reduces codereplication and enhances flexibility. [...]
As I'm not sure what kind of implementation you're thinking of, I can't respond to this. So far as I can tell, my design is doing what you describe for policy-based design.
There is a great deal of code replication in the current implementation of xint::integer_t. [...] This skeleton (and some variations of it) occurs over and over again only to propagate the call of the function to the implementing class at positions #1 and #2.
integer_t handles some options, and passes the data to the implementing class for others. It was the best solution I could find to handle all options.
Trying to be consistent with my own request ...
"At the same time I'd like to call on the boost community to support Chad and to see an Integer library as an opportunity to develop more common understanding how a state of the art generic design looks like in this specific case."
... I invested some work to make my suggestion about good design more concrete. I will give you a small example of a policy based design that is directly related to some problems of code replication and insufficient separation of concerns in your library. At the same time I hope it'll help to understand policy based design, which includes getting a better understanding for myself. The only source of PDB that I've been using so far is Andrei's book from 2001. [Andrei Alexandrescu 2001, Moden C++ Design] But I found the page on wikipedia informative as well. http://en.wikipedia.org/wiki/Policy-based_design Maybe others can contribute more good sources, I did not research. Andrei's book has been really enlightening for me. I've never read a book about programming with so much delight. I can highly recommend it. As for the example. I picked one aspect of your design, the option for nothrow, that controls the handling of nan. Here I've criticized code replication in your code like if (Nothrow) {if (b.is_nan()) ... if (!is_nan()) { ... }} else {...} that reoccurs a lot in the implementation of integer_t. Using policy based design, we try to encapsulate all aspects of the code that relates to the handling of nans in a policy class. So we try to separate the concern "handling nan" from other parts of a class. In this case aint (not xint ;) //========================================================= // Using policies, we want to handle nan in a "nany" or // a "manly" way (manly: ignore it all together) struct nany; // Takes care for the nasty nan struct manly; // No, we don't want this template<class, class> class aint; // a int with nan policy // Meta function for naniness. template<class Type> struct is_nany { static const bool value = false; }; template<class Rep> // a int with nany policy is_nany struct is_nany<aint<Rep, nany> > { static const bool value = true; }; template<class Type> bool is_nan(Type const& value) { // Not perfect ... ok. for the example return value ==( numeric_limits<Type>::has_quiet_NaN ? (numeric_limits<Type>::quiet_NaN)() : (numeric_limits<Type>::max)() ); } // An int class with NaNPolicy: Rep is supposed to be some // integer implementation, including limitless integers // NaNPolicy encapsulates nan-handling. template<class Rep, class NaNPolicy = manly> class aint // no sunshine when she's gone { public: aint(): _value(){} aint(Rep const& val): _value(val){} aint& operator += (aint const& y) { NaNPolicy::plus_assign(_value, y._value); return *this; } Rep value(){ return _value; } private: Rep _value; }; // Finally two different NaN-policy classes struct nany { template<class Rep> inline static void plus_assign(Rep& x, Rep const& y) { if (is_nan(x)) ; else if(is_nan(y)) x = y; else x += y; } }; struct manly { template<class Rep> inline static void plus_assign(Rep& x, Rep const& y) { x += y; } }; BOOST_AUTO_TEST_CASE(nan_policy_study) { // No NaN protection aint<long> ago; // A no throw int with NaN protection aint<short, nany> sun(2); aint<short, nany> shine(7); sun += shine; cout << sun.value() << endl; // I is generic because it is suitable for all kinds of // integer types Rep including say xint::integer_t types aint<xint::integer, nany> ax_i; } //========================================================= 1. Encapsulation: The code necessary for the handling of nans is either encapsulated in the policy class, or it uses some meta code that is globally available. 2. Non intrusive: This code does not require changes in the class Rep, that implements the basic semantics. 3. Generic: So, apart from very little code around the existence and test of the NaN-element, the policy based design works for all integer implementations Rep that are model of a common integer concept, which is implicitly given in this case. 4. Abstraction: Moreover separation of concerns leads to abstraction here. We discover that this kind of "nan closure" not only works for integers but also for floting point numbers or continuous numbers like e.g. boost::rational. Regards, Joachim -- Interval Container Library [Boost.Icl] http://www.joachim-faulhaber.de