
Hi Luke,
Please feel free to critique the code. I want to make sure I've got everything right before I rewrite the library.
In an eralier post you menioned that your interface was better than requiring a point model to have member functions x() and y(). That's absolutely true, but the conclusion is that such a concept definition is not generic so it's the concept itself which is wrong, not the use of concepts (you know this of course). We would never propose such a concept precisely because you can't use concrete types *as is*. The fundamental idea of generic programming is the use of "external" adpatation. To that effect, your concept definition is way better than one requiring members like x() or y() and I also noticed in the attached sample code that there are no wrappers: this is very good and fundamental since having to create an instance of a point_traits<T> passing a concrete point type wouldn't be in the spirit of good generic programming and we would complain. Still, there are some points to discuss. Take this for instance: template <typename T> class point_traits { public: typedef typename T::coordinate_type coordinate_type; static inline coordinate_type get(const T& point, orientation_2d orient) { return point.get(orient); } static inline void set(T& point, orientation_2d orient, coordinate_type value) { point.set(orient, value); } static inline T construct(coordinate_type x_value, coordinate_type y_value) { return T(x_value, y_value); } }; No doubt this is generic as intended, but IMO it is a bit monolthic and forces an unnnecesary verbose syntax. I would rather have point_traits define types but not functions: template <typename T> struct point_traits { typedef typename T::coordinate_type coordinate_type; } becasue this separation gives you more lattitud to decide how to define the functions. For example, you can have: struct point_concept { template<class T> typename point_traits<T>::coordinate_type static inline get( T const& point, orientation_2d orient ) { return point.get(orient); } } ; which users can specialize for concrete types just as in your case. The difference becomes apparent in the user side syntax: You can type this; point_concept::get(point1, HORIZONTAL) instead of: point_traits<T>::get(point1, HORIZONTAL) which can be quite significant when T is syntactically much more than just 'T'. Now of course I would have free functions instead: template<class T> typename point_traits<T>::coordinate_type static inline get_component( T const& point, orientation_2d orient ) { return point.get(orient); } Because free functions allows you to refactor your concept hierarchy with minimal impact on the end user. Let me explain this: On an upcoming dicussion we would have to argue about the concepts themselves (in the abstract, regardless of the specific C++ interface). Questions like: Does a point has coordinates or is there a coordinate-free point concept separatedly from the one with coordinates? Does the library includes vectors as well? Since, from a certain POV, both vectors and points have coordinates, should there be a "cartesian" concept which is nothing but a tuple of components? What about dimensions? Is a certain point concept for 2D? Is there a separate point concept for 3D? Such a discussion would affect the very definition of the existing concepts and would result in a refactoring of the concepts design. Now, say you haven't yet considered any of the above so you just define your point concept as you do now. This fixes the following interface: point_concept::get(point1, HORIZONTAL) which ties the operation to extract a component of a point with a *specific* concept via the nesting of the function in a class that corresponds to that particular concept. Now say that you want to add vectors to the library, and vectors have x,y components as well: what do you do *now*? You could create yet another accessor with essentially the same method vector_concept::get(vector1, HORIZONTAL) but then users would have to specialize both point_concept and vector_concept even if their concrete class is the same for both. Or perhaps you define a new concept, say cartesian, and deprecate point_concept::get in favor of cartesian::get (or even break compatibility if you are like me and never bargain on refactoring, specially these days when method renaming is a snap in most development enviroments) Free functions OTOH gives you much more flexibility to evolve the design because users that were calling get_component(q,orient) won't have to change that call even if there are now new concepts for which point is just a refinement. Of course the discussion between using free functions instead of member functions is not particular of generic programming but much more general. Yet it is particularly important in generic programming because users have to specialize the functions that instrument the concepts interface and free functions are totally independent hence the most flexible. Granted, in a perfectly tied up and "closed" design, this wouldn't matter at all, but in the case of your library I think this flexibility is very important because in the current form the library is not too general so chances are it will stretch and be refactor over time as other domains are added to it. Best -- Fernando Cacciola SciSoft http://scisoft-consulting.com http://fcacciola.50webs.com http://groups.google.com/group/cppba