Re: [boost] [GTL] - geometric template library - determininginterest

John Femiani wrote:
Count me as interested in any attempt at a free generic geometry library.
Is this purely 'rectilinear' -- I mean, when you say polygons do you mean any kind of polygon or only the kinds of polygons formed by the union of axis-aligned rectangles? Could I find the intersection of a star and a triangle?
Gyuszi Suto wrote:
The polygons need to be formed by union of axis-aligned rectangles, yes. In addition to that, GTL supports 45 degree polygons as well. Can GTL intersect a star and a triangle? If both are limited to rectilinear or 45 degreee edges, yes, otherwise no.
There is the strong possibility that I will be extending the GTL capabilities beyond 45 degree to allow arbitrary angles with the goal of providing best in class performance with a generic and productive interface. As we are all aware, this leads to the need to provide a mechanism to ensure numerical robustness at considerable cost in runtime. That mechanism would obviously include a generic interface for specifying the internal numerical data type to be used by the algorithm, with a default provided by the library. However, our intention is not to provide a comprehensive geometry library, which would be too broad in scope, but rather a starting point for generic geometry that the community can participate in and extend in the most useful directions. In looking at the recent submissions to boost related to geometry there is a fair amount of overlap with our library, particularly in what I call the basic types such as point2d. The ideal outcome from my point of view is that we all benefit from a synthesis of ideas and craft a boost geometry library together that goes beyond the code we will initially submit and will continue to be enhanced and extended with the participation of the community over time. Lucanus Simonson

On Wednesday 03 October 2007, Simonson, Lucanus J wrote:
John Femiani wrote:
Count me as interested in any attempt at a free generic geometry library.
Is this purely 'rectilinear' -- I mean, when you say polygons do you mean any kind of polygon or only the kinds of polygons formed by the union of axis-aligned rectangles? Could I find the intersection of a star and a triangle? [...]
Has anyone gone to look at the JTS library <http://www.vividsolutions.com/jts/jtshome.htm>? I had a (short) opportunity to use it, and quite liked the design. It's Java, so I hated everything else. :-) However, there's at least one C++ port out there (GEOS: <http://geos.refractions.net/>). Possibly-unreliable rumor had it that GEOS worked but was a straight Java-to-C++ port, and therefore didn't have the performance it could have. AFAICT JTS algorithms Do It Right, where "Right" is "fairly close to as right as the computational geometry community knows how to make it". If I won the lottery tomorrow I'd grab it and see what could be done. No lottery winnings are likely to come my way, though. So I thought you folks in this conversation might be interested in taking a look. -- Dave Steffen, Ph.D. "I say we invite opportunity inside Software Engineer IV for a nice cup of tea, then hit her Numerica Corporation on the head and steal her purse." ph (970) 461-2000 x227 dgsteffen@numerica.us -- Shlock Mercenary

Simonson, Lucanus J wrote:
In looking at the recent submissions to boost related to geometry there is a fair amount of overlap with our library, particularly in what I call the basic types such as point2d. The ideal outcome from my point of view is that we all benefit from a synthesis of ideas and craft a boost geometry library together that goes beyond the code we will initially submit and will continue to be enhanced and extended with the participation of the community over time.
Yes, absolutely. We need to decide what the foundations should be, and the Point type is one of the most basic. Could you post your point2d class? Some of the choices are: * Coordinate type: it's pretty clear to me that that should be a template parameter, for which you can supply an integer, fixed-point or floating-point type. Some algorithms will depend on particular types being used, e.g. my space-filling-curves code doesn't work with floating point, but that doesn't mean we have to prohibit such kinds of points entirely. * Homogeneous vs. heterogeneous coordinate types: for example, in a mapping application, latitude and longitude are (almost) the same type, whereas altitude has an entirely different range and might benefit from using a different type e.g. a different fixed-point scale factor. So do we have one template parameter or n template parameters? * Fixed or variable number of coordinates: I'm happy with 2d and sometimes 3d points and using distinct types for them, but some people think in higher dimensions and need points with arbitrary numbers of dimensions. * xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both? * Accessors or simple variables: should I write p.x or p.x() or p.get_x() ? * Member functions or free functions: p.distance_to(q) or distance_between(p,q) ? I'm sure there are more. Phil.

Phil Endecott wrote:
Simonson, Lucanus J wrote:
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both?
Yes! Use fusion to do the mapping, making all your structs, arrays or whatnots, whatever they are, compatible. You deal with them in a uniform manner. You don't care if the point type (for example) is from library A or library B. It just works. Here's an example: namespace A // library A { struct point { int x; int y; }; } namespace B // library B { struct Point { float y; // y comes first! float x; }; } namespace C // library B { typedef boost::array<int, 2> Point; } Now, let's adapt these structs to make them tuples (boost::array is already adapted without doing anything else): BOOST_FUSION_ADAPT_STRUCT( A::point, (int, x) (int, y) ) BOOST_FUSION_ADAPT_STRUCT( B::point, (float, x) (float, y) ) Now, in your generic code, you simply refer to X and Y as: get<1>(p); // x get<2>(p); // y regardless if p is a boost::array, a boost::tuple, a B::Point, or an A::point. They are all compatible. And, the bonus is that because they are now first class fusion sequences (A::point and B::point), all fusion iterators and algorithms can be used. Yes, you can iterate through all the dimensions! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Now, in your generic code, you simply refer to X and Y as:
get<1>(p); // x get<2>(p); // y
Ooops, I meant: get<0>(p); // x get<1>(p); // y of course! Cheers! -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Phil Endecott wrote:
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both?
Yes! Use fusion to do the mapping, making all your structs, arrays or whatnots, whatever they are, compatible.
I was imagining something more lightweight, like a union... There's also the possibility of simply defining implicit conversions between the two styles. But a better solution would be to decide from the outset that one style is "right" and the other is "wrong", so only one needs to be supported and no conversions are needed. (I mean that partly tongue-in-cheek.) Phil.

Phil Endecott wrote:
Joel de Guzman wrote:
Phil Endecott wrote:
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both? Yes! Use fusion to do the mapping, making all your structs, arrays or whatnots, whatever they are, compatible.
I was imagining something more lightweight, like a union...
There's also the possibility of simply defining implicit conversions between the two styles.
But a better solution would be to decide from the outset that one style is "right" and the other is "wrong", so only one needs to be supported and no conversions are needed. (I mean that partly tongue-in-cheek.)
Have a look at: http://www.gamedev.net/community/forums/topic.asp?topic_id=261920 - Michael Marcin

Michael Marcin wrote:
Phil Endecott wrote:
Joel de Guzman wrote:
Phil Endecott wrote:
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both? Yes! Use fusion to do the mapping, making all your structs, arrays or whatnots, whatever they are, compatible.
I was imagining something more lightweight, like a union...
There's also the possibility of simply defining implicit conversions between the two styles.
But a better solution would be to decide from the outset that one style is "right" and the other is "wrong", so only one needs to be supported and no conversions are needed. (I mean that partly tongue-in-cheek.)
Have a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id=261920
Yes, a very good page showing several solutions: 1. A vector of member pointers (may have some overhead). 2. Anonymous structs and unions (may be non-standard). 3. x, y and z implemented as references (makes object bigger). 4. Relying on (&x)[1] pointing to y. _IF_ 4 really is guaranteed to work portably (as its author claims), it would get my vote: template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } }; ...what's the catch? One complexity is how point2d and point3d types like this would interoperate with a generic N-dimensional point: template <typename T, int N> struct point : public array<T,N> // or something like that Is it possible specialise point<T,N> for N==2 and N==3 to add the xyz stuff, and then typedef to the point2|3d names? Phil.

On 10/4/07, Phil Endecott <spam_from_boost_dev@chezphil.org> wrote:
Michael Marcin wrote:
Have a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id=261920
Yes, a very good page showing several solutions:
1. A vector of member pointers (may have some overhead). 2. Anonymous structs and unions (may be non-standard). 3. x, y and z implemented as references (makes object bigger). 4. Relying on (&x)[1] pointing to y.
For actual asm output, see http://www.gamedev.net/community/forums/topic.asp?topic_id=230443&PageSize=25&WhichPage=2 for the "overhead" of option 1.
_IF_ 4 really is guaranteed to work portably (as its author claims), it would get my vote:
template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } };
...what's the catch?
I'm almost positive the author was wrong in claiming that it is portable. Here's an old thread about the issue: http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/df5bc148a994d511/36c133bbb606bece?lnk=gst&q=point+operator%5B%5D+x+y+z&rnum=6#36c133bbb606bece --Michael Fawcett

About portability this is what the standard (9.2/12) says :
Nonstatic data members of a (non-union) class declared without an intervening /access-specifier/ are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an /access-specifier/ is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes.
as recently pointed out to me by Sebastian Redl.
template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } };
In the struct point2d there is no virtual functions, between data members there is no intervening access specifier, so if sizeof(T) is a multiple of the used alignment the standard guarantes that such code is valid, and this condition is verified for T = int, long, float, double using the default alignment (4 bytes). Regards, Marco Cecchetti On Thu, 04 Oct 2007 22:15:33 +0200, Michael Fawcett <michael.fawcett@gmail.com> wrote:
On 10/4/07, Phil Endecott <spam_from_boost_dev@chezphil.org> wrote:
Michael Marcin wrote:
Have a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id=261920
Yes, a very good page showing several solutions:
1. A vector of member pointers (may have some overhead). 2. Anonymous structs and unions (may be non-standard). 3. x, y and z implemented as references (makes object bigger). 4. Relying on (&x)[1] pointing to y.
For actual asm output, see http://www.gamedev.net/community/forums/topic.asp?topic_id=230443&PageSize=25&WhichPage=2
for the "overhead" of option 1.
_IF_ 4 really is guaranteed to work portably (as its author claims), it would get my vote:
template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } };
...what's the catch?
I'm almost positive the author was wrong in claiming that it is portable. Here's an old thread about the issue:
--Michael Fawcett _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

On 10/5/07, Marco <mrcekets@gmail.com> wrote:
About portability this is what the standard (9.2/12) says :
Nonstatic data members of a (non-union) class declared without an intervening /access-specifier/ are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an /access-specifier/ is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes.
as recently pointed out to me by Sebastian Redl.
template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } };
In the struct point2d there is no virtual functions, between data members there is no intervening access specifier, so if sizeof(T) is a multiple of the used alignment the standard guarantes that such code is valid, and this condition is verified for T = int, long, float, double using the default alignment (4 bytes).
I do not think that the standard guarantees the lack of padding between 'x' and 'y'. IIRC You are only guaranteed that &x < &y, not that &x +1 == &y. gpd

On Fri, 05 Oct 2007 00:40:24 +0200, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On 10/5/07, Marco <mrcekets@gmail.com> wrote:
About portability this is what the standard (9.2/12) says :
Nonstatic data members of a (non-union) class declared without an intervening /access-specifier/ are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an /access-specifier/ is unspecified. Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions and virtual base classes.
as recently pointed out to me by Sebastian Redl.
template <typename T> struct point2d { T x, y; T& operator[](int i) { return (&x)[i]; } };
In the struct point2d there is no virtual functions, between data members there is no intervening access specifier, so if sizeof(T) is a multiple of the used alignment the standard guarantes that such code is valid, and this condition is verified for T = int, long, float, double using the default alignment (4 bytes).
I do not think that the standard guarantees the lack of padding between 'x' and 'y'. IIRC You are only guaranteed that &x < &y, not that &x +1 == &y.
gpd
IMO, it's a subtle question. Formally you're right about what standard guarantees, but in the above struct members x, y have the same type T, so data alignment require no padding at all. What should be put between x and y ? IMO padding is required to manage data alignment. Are there other cases where padding is needed ? Regards, Marco -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

"Phil Endecott" <spam_from_boost_dev@chezphil.org> writes:
http://www.gamedev.net/community/forums/topic.asp?topic_id=261920
Yes, a very good page showing several solutions:
1. A vector of member pointers (may have some overhead). 2. Anonymous structs and unions (may be non-standard). 3. x, y and z implemented as references (makes object bigger). 4. Relying on (&x)[1] pointing to y.
Regarding (2), note that using a union can cause severe performance degradation with some compilers (recent versions of gcc, at least). I guess that the compiler makes pessimistic assumptions about aliasing when it sees a union. As an example: I have some code that offers both ".x/.y/.z" and array-style access to the members of 3d vectors. The code originally only used ".x/.y/.z" fields. When I first added the "array-style" feature, I used a construct like: union { struct { float x, y, z; }; float els[3]; }; float &operator[] (unsigned i) { return els[i]; } const float &operator[] (unsigned i) const { return els[i]; } The resulting object code was _much_ worse than the original. I subsequently changed the code to use your option (4): T &operator[] (unsigned i) { return (&x)[i]; } const T &operator[] (unsigned i) const { return (&x)[i]; } And the resulting object code was much better -- basically the same as the original .x/.y/.z fields-only code. [I guess that doing this could potentially cause the compiler to miss some aliasing that it shouldn't, but in practice this isn't a problem, as all my code uses either the field-style access or array-style access, and never mixes the two.] Option (3) doesn't really seem practical to me given that such small vectors are used very heavily, and often in great numbers. I dunno about option (1): on first glance, it looks even more hacky than the other options, and the the use of a global variable seems like it might cause pessimal assumptions by the compiler (though at least, hopefully, that would only affect the array-style access, not all access like option (2) does). -Miles -- "Suppose He doesn't give a shit? Suppose there is a God but He just doesn't give a shit?" [George Carlin]

Miles Bader wrote:
"Phil Endecott" <spam_from_boost_dev@chezphil.org> writes:
http://www.gamedev.net/community/forums/topic.asp?topic_id=261920 Yes, a very good page showing several solutions:
1. A vector of member pointers (may have some overhead). 2. Anonymous structs and unions (may be non-standard). 3. x, y and z implemented as references (makes object bigger). 4. Relying on (&x)[1] pointing to y.
Regarding (2), note that using a union can cause severe performance degradation with some compilers (recent versions of gcc, at least). I guess that the compiler makes pessimistic assumptions about aliasing when it sees a union.
As an example: I have some code that offers both ".x/.y/.z" and array-style access to the members of 3d vectors.
The code originally only used ".x/.y/.z" fields. When I first added the "array-style" feature, I used a construct like:
union { struct { float x, y, z; }; float els[3]; }; float &operator[] (unsigned i) { return els[i]; } const float &operator[] (unsigned i) const { return els[i]; }
The resulting object code was _much_ worse than the original.
Not to mention that you can't put non-POD types into a union which makes this option a non-starter for generic code. - Michael Marcin

Phil Endecott wrote:
Joel de Guzman wrote:
Phil Endecott wrote:
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both? Yes! Use fusion to do the mapping, making all your structs, arrays or whatnots, whatever they are, compatible.
I was imagining something more lightweight, like a union...
There's also the possibility of simply defining implicit conversions between the two styles.
But a better solution would be to decide from the outset that one
style
is "right" and the other is "wrong", so only one needs to be supported and no conversions are needed. (I mean that partly tongue-in-cheek.)
Have a look at:
http://www.gamedev.net/community/forums/topic.asp?topic_id&1920
- Michael Marcin
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion. i.e. template <int Index> float get(MyPoint & p) {return p[Index];} OR template <> float get<0>(MyPoint & p) {return p.x;} -- John

John Femiani wrote:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
i.e. template <int Index> float get(MyPoint & p) {return p[Index];} OR template <> float get<0>(MyPoint & p) {return p.x;}
Dependency is indeed an issue. Sure you can get by with the simple interface above. I think that's the barest minimum. Perhaps the next step is to provide an optional mapping to fusion when explicitly specified by the client. This would be desirable in cases where the client directly or indirectly uses fusion anyway. The advantage in making your structs full fledged fusion sequences will become apparent when you go into more generic programming. The simplest would be, say, iterating to all the (possibly heterogeneous) dimensions and applying some generic algorithms on them. All that being said, while taken as a whole, fusion might indeed be big, the core code that deals with iterators and adopting is rather lightweight. You only pay for what you use. The iterators and adapters are only two cents a piece ;-) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

John wrote:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
i.e. template <int Index> float get(MyPoint & p) {return p[Index];} OR template <> float get<0>(MyPoint & p) {return p.x;}
Dependency is an issue, since my library depends only on the STL, which ships with the compiler and compiles currently in gcc 3.2.2, 3.4.2, and 4.2.1; icc 9 and 10 and most painfully Visual Studio 2003/2005. The barrier to adoption into a legacy build system is extremely low. Adding a dependency, even to a boost library, would actually hurt my ability to integrate it into legacy applications. Moreover, the technique you are proposing works fine at compile time, but won't work if the axis of the coordinate you are accessing is a runtime parameter: int my_axis = 0; get<my_axis>(pt); will throw an error. We specify the axis we access at run time. If we specify a constant it should compile away and be light weight. gcc 4.2.1 still needs us to play with the compiler flags to get decent inlining. pt.get(orient.getPerpendicular()); //orientation determined at run time. My scanline algorithm actually parameterizes the orientation of the scanline at runtime, so you can sweep left to right or bottom to top. Lucanus Simonson

Simonson, Lucanus J wrote:
John wrote:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
i.e. template <int Index> float get(MyPoint & p) {return p[Index];} OR template <> float get<0>(MyPoint & p) {return p.x;}
Dependency is an issue, since my library depends only on the STL, which ships with the compiler and compiles currently in gcc 3.2.2, 3.4.2, and 4.2.1; icc 9 and 10 and most painfully Visual Studio 2003/2005. The barrier to adoption into a legacy build system is extremely low. Adding a dependency, even to a boost library, would actually hurt my ability to integrate it into legacy applications.
Right. Ok. That's a valid concern.
Moreover, the technique you are proposing works fine at compile time, but won't work if the axis of the coordinate you are accessing is a runtime parameter: int my_axis = 0; get<my_axis>(pt); will throw an error. We specify the axis we access at run time. If we specify a constant it should compile away and be light weight. gcc 4.2.1 still needs us to play with the compiler flags to get decent inlining. pt.get(orient.getPerpendicular()); //orientation determined at run time. My scanline algorithm actually parameterizes the orientation of the scanline at runtime, so you can sweep left to right or bottom to top.
Ok. Well, then if accessing the index using runtime int is a requirement, then your only option is an array of some sort indeed. Minus one for genericity. Forget structs, tuples, interoperability and adoptation of other systems. Forget heterogenous dimensions. Hmmm. Seems like this type of rigid API is not to my taste. To me it's like requiring that all STL containers be indexable with ints. Perhaps there's merit in limiting the library this way. Extreme performance? Sure, ok, but then again, what really amazes me are libraries like GIL, or STL that provide extreme performance without being rigid. My opinion only. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/5/07, Joel de Guzman <joel@boost-consulting.com> wrote:
Simonson, Lucanus J wrote:
John wrote:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
i.e. template <int Index> float get(MyPoint & p) {return p[Index];} OR template <> float get<0>(MyPoint & p) {return p.x;}
Dependency is an issue, since my library depends only on the STL, which ships with the compiler and compiles currently in gcc 3.2.2, 3.4.2, and 4.2.1; icc 9 and 10 and most painfully Visual Studio 2003/2005. The barrier to adoption into a legacy build system is extremely low. Adding a dependency, even to a boost library, would actually hurt my ability to integrate it into legacy applications.
Right. Ok. That's a valid concern.
Well, the above code doesn't work for heterogeneous vectors. So regardless of his opinion on introducing dependencies, it one wishes to support heterogeneous vectors, I think one should probably just bring in Fusion.
Moreover, the technique you are proposing works fine at compile time, but won't work if the axis of the coordinate you are accessing is a runtime parameter: int my_axis = 0; get<my_axis>(pt); will throw an error. We specify the axis we access at run time. If we specify a constant it should compile away and be light weight. gcc 4.2.1 still needs us to play with the compiler flags to get decent inlining. pt.get(orient.getPerpendicular()); //orientation determined at run time. My scanline algorithm actually parameterizes the orientation of the scanline at runtime, so you can sweep left to right or bottom to top.
Ok. Well, then if accessing the index using runtime int is a requirement, then your only option is an array of some sort indeed.
Minus one for genericity. Forget structs, tuples, interoperability and adoptation of other systems. Forget heterogenous dimensions.
Hmmm. Seems like this type of rigid API is not to my taste. To me it's like requiring that all STL containers be indexable with ints. Perhaps there's merit in limiting the library this way. Extreme performance? Sure, ok, but then again, what really amazes me are libraries like GIL, or STL that provide extreme performance without being rigid.
I haven't had a chance to mess around with Fusion yet, but if it could somehow be integrated into the attached, I think we would have the best of all the worlds. -all the goodies that come with a Fusion sequence -array access when the vector is homogeneous -swizzle syntax -doesn't rely on non-standard behavior -zero (to very little) overhead - I would love if someone who knew asm well could look at the generated instructions in the attached (with optimizations on) and confirm this. --Michael Fawcett P.S. - I had to rename the extension to get it passed our firewall, but it's a .zip file, so please rename it. I can also upload it to the Vault if that's easier.

"John Femiani" <JOHN.FEMIANI@asu.edu> writes:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
template <int Index> float get(MyPoint & p) {return p[Index];} template <> float get<0>(MyPoint & p) {return p.x;}
How does this work with non-constant indices? That's a significant reason why array-style access is useful ... -Miles -- "I distrust a research person who is always obviously busy on a task." --Robert Frosch, VP, GM Research

Miles Bader wrote:
"John Femiani" <JOHN.FEMIANI@asu.edu> writes:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
template <int Index> float get(MyPoint & p) {return p[Index];} template <> float get<0>(MyPoint & p) {return p.x;}
How does this work with non-constant indices? That's a significant reason why array-style access is useful ...
And is also a significant reason why it is so limiting. It's a trade off -- a design choice akin to requiring all STL sequences and containers be indexable by a runtime int. If you want to make full use of concepts, go all the way! You can make several levels of concepts with increasing levels of restrictions. Somewhere near the bottom of the concept hierarchy, you can definitely add an IndexablePoint concept, say. For many a generic algorithm that works on points however, I'd say that that severe requirement is not needed -- just as much as most STL algorithms do not require RandomAccess. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

-----Original Message----- From: miles.bader@necel.com [mailto:miles.bader@necel.com] Sent: Thursday, October 04, 2007 8:47 PM To: John Femiani Cc: boost@lists.boost.org Subject: Re: [GTL] - geometric template library - determininginterest
"John Femiani" <JOHN.FEMIANI@asu.edu> writes:
What is not lightweight about the get<0>(pt) syntax? Doesn't it compile away? Is the issue a dependency on another library -- because the get<0>(pt) syntax seems really easy to provide without bothering with Fusion.
template <int Index> float get(MyPoint & p) {return p[Index];} template <> float get<0>(MyPoint & p) {return p.x;}
How does this work with non-constant indices? That's a significant reason why array-style access is useful ...
-Miles
Array access has it own problems; I think we would need to accommodate both. I am not too familiar with fusion; but I have used GIL which has concepts for heterogeneous as well as homogeneous types. The most generic type of access is obtained by something like the get<> template function below (but GIL calls it at_c<>). This can be used for all types, but it requires compile-time knowledge of the index. There is another, more restrictive, concept for homogenous types only that also allows the brackets ([]) to be used. As a developer you decide whether your algorithm fundamentally requires a homogeneous type or not and you document/enforce this through the appropriate concepts, but if you can support the get<> syntax your algorithms that require points will be applicable to more types. I suspect that with a little cleverness most point operations can be done without array-style indices. For example; with the get<> syntax it easy to add a read-only homogenous coordinate without modifying the underlying point type: float get<3>(MyPnt2D&) {return 1;} float get<3>(MyVec2D&) {return 0;} //"Point at infinity" If you chose the [] operators I think you would have to tack an extra '1' to each object OR put some kind of 'if' statement that would be evaluated for each access to operator[]. If we want boost to have a point class I think it will really have to be a set of point adapters and point concepts that work for existing types. There are too many points out there that we would have to interact with, both outside of boost and also within boost. For instance it would be nice if algorithms worked with both Boost.Point and the CGAL point. -- John

John wrote:
If we want boost to have a point class I think it will really have to be a set of point adapters and point concepts that work for existing types. There are too many points out there that we would have to interact with, both outside of boost and also within boost. For instance it would be nice if algorithms worked with both Boost.Point and the CGAL point.
That is exactly what I am proposing. You hit the nail on the head, there are too many points out there that we would have to interact with. That is the problem I'm solving, that is why I'm submitting the library to boost. assert(boost::point_concept<cgal::Point> cgalpt(10,20) == boost::point(10, 20)); and better yet //construct a cgal polygon data structure with the boost polygon constructor and assert that it is equal to the boost polygon data structure constructed from the same input vertex sequence. assert(boost::polygon_concept<cgal::Polygon> cgalpoly(itBegin, itEnd) == boost::polygon(itBegin, itEnd)); Smooth as butter. Luke

John wrote:
If we want boost to have a point class I think it will really have to be a set of point adapters and point concepts that work for existing types. There are too many points out there that we would have to interact with, both outside of boost and also within boost. For instance it would be nice if algorithms worked with both Boost.Point and the CGAL point.
That is exactly what I am proposing. You hit the nail on the head, there are too many points out there that we would have to interact with. That is the problem I'm solving, that is why I'm submitting the
library
to boost. assert(boost::point_concept<cgal::Point> cgalpt(10,20) == boost::point(10, 20));
and better yet
//construct a cgal polygon data structure with the boost polygon constructor and assert that it is equal to the boost polygon data structure constructed from the same input vertex sequence. assert(boost::polygon_concept<cgal::Polygon> cgalpoly(itBegin, itEnd) == boost::polygon(itBegin, itEnd));
Smooth as butter.
Luke
Hmm... I hope I am not revealing my ignorance too much here but I have not seen concepts used that way before. In my experience they are used with some macros to force an understandable error at compile time when a data type does not support the required syntax. Do you have some code I can see so I can maybe understand better? -- John

That is exactly what I am proposing. You hit the nail on the head, there are too many points out there that we would have to interact with. That is the problem I'm solving, that is why I'm submitting the library to boost. assert(boost::point_concept<cgal::Point> cgalpt(10,20) == boost::point(10, 20));
and better yet
//construct a cgal polygon data structure with the boost polygon constructor and assert that it is equal to the boost polygon data structure constructed from the same input vertex sequence. assert(boost::polygon_concept<cgal::Polygon> cgalpoly(itBegin, itEnd) == boost::polygon(itBegin, itEnd));
Smooth as butter.
Luke
John wrote:
Hmm... I hope I am not revealing my ignorance too much here but I have not seen concepts used that way before. In my experience they are used with some macros to force an understandable error at compile time when a data type does not support the required syntax. Do you have some code I can see so I can maybe understand better?
If you think about it, if all concepts were good for was giving us shorter, clearer error msgs they wouldn't be very worthwhile to add to the language. You are not revealing ignorance. To my knowledge people are not using concepts this way before, that is what makes what I'm doing interesting. Bjarne didn't anticipate all the ways the language would be used, and that is what boost is about. I think he does understand the usefulness of concepts (beyond simply cleaning up template errors) but it is hard for him to communicate that to the community until someone like boost shows people what the language features he put in there are good for. You know he told me that it was an uphill battle to get inheritance from the template parameter into the C++ standard in the first place. I about fell of my chair because I remember when I learned from Gysuzi that it was a supported feature of the language I was literally jumping for joy. When I talked to Bjarne last year when he visited intel he suggested that we should take my library and use it as a case study for the improvement adding concepts to the language in the 2009 standard will make. For starters my errors will become more readable.... I have an alpha build of the compiler from the last boost conference, but was too busy implementing the support for 45 degree polygon edges to port my library to use the new language features. My long term goal is to release a version of the library implemented in terms of the concept_map and other features he is adding to the language at the same time the new standard is coming out, that way people will see what is going into the language and how it is being used by the example of the library. Boost is absolutely the right place for people to find that example. People had no idea what templates could really do until boost showed them. That is why I say it doesn't really matter what the library does (it happens to do what my boss needed it to do so that our chips can be built) so much as how, so that people can learn how to do the same in their library programming. Intel legal policy prohibits me from releasing even snippets of code, but I am free to type C++ into an email. Gyuszi already posted some example of how it works, and so have I. I'm trying to fast track license approval, so please be patient. There is about 23,000 lines of code in my library in 60 header files. If represents about one full year of development effort on my part. It is header file only and thread safe. I have integrated it into four different legacy applications through the polygon concept and have a group of native users working with its built in data types to develop new application level code (that is what Gyuszi is doing.) This is my day job and Concepts have made my life easier, my work more productive. class point_data { ... }; template <class T> class point_concept_map {}; template <> class point_concept_map<point_data> { /* define get, set and construct static functions in terms of point_data */ }; /* public because visual studio doesn't support the standard correctly for private inheritance from template argument*/ template <class T> class point_concept : public T { /*define get, set and construct in terms of point_concept_map function and all other member functions in terms of get, set and construct */ }; typedef point point_concept<point_data>; point& foo(point& pt) { //set returns a reference to *this for chaining purposes return pt.set(HORIZONTAL, mypoint.get(VERTICAL)/2); } struct LegacyPoint { int x, int y }; template <> class point_concept_map<LegacyPoint> { /* define in terms of LegacyPoint */ }; template <class T> point_concept<T>& foo2(point_concept<T>& pt) { return pt.set(HORIZONTAL, mypoint.get(VERTICAL/2); } void bar() { LegacyPoint pt; pt.y = 10; foo2(point_concept<LegacyPoint>::mimic(pt)); assert(pt.x == 5); point pt2(0, 10); foo2(pt2); assert(pt2 == point_concept<LegacyPoint>::mimic(pt)); } If you clean up and fill in some of the blanks you ought to be able to get the design pattern and unit test code descriptions I have posted here to compile and work. Lucanus Simonson

On 10/5/07, Simonson, Lucanus J <lucanus.j.simonson@intel.com> wrote:
If you clean up and fill in some of the blanks you ought to be able to get the design pattern and unit test code descriptions I have posted here to compile and work.
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is: 1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ? Thanks Marco

Marco wrote:
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Yes, though I would add that the intention is to use it with classes b1 through bN of libraries B1 through BN so that the effort of making the library generic is worthwhile. Class a inherits from each of the classes b1 through bN through its template parameter. In this way it is as useful as making class a the common base class of b1 through bN, but is not intrusive and leaves the code of libraries B1 through BN untouched. This inheriting one class from many allows us to unify the disparate semantics of many different types that are conceptually similar. I have found it very useful in my day to day work since I end up being the person integrating my library into existing code bases in addition to authoring it. Lucanus Simonson

Simonson, Lucanus J wrote:
Marco wrote:
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Yes, though I would add that the intention is to use it with classes b1 through bN of libraries B1 through BN so that the effort of making the library generic is worthwhile. Class a inherits from each of the classes b1 through bN through its template parameter. In this way it is as useful as making class a the common base class of b1 through bN, but is not intrusive and leaves the code of libraries B1 through BN untouched. This inheriting one class from many allows us to unify the disparate semantics of many different types that are conceptually similar. I have found it very useful in my day to day work since I end up being the person integrating my library into existing code bases in addition to authoring it.
It is possible to do this without inheritance. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

On 10/7/07, Simonson, Lucanus J <lucanus.j.simonson@intel.com> wrote:
Marco wrote:
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Yes, though I would add that the intention is to use it with classes b1 through bN of libraries B1 through BN so that the effort of making the library generic is worthwhile. Class a inherits from each of the classes b1 through bN through its template parameter. In this way it is as useful as making class a the common base class of b1 through bN, but is not intrusive and leaves the code of libraries B1 through BN untouched. This inheriting one class from many allows us to unify the disparate semantics of many different types that are conceptually similar. I have found it very useful in my day to day work since I end up being the person integrating my library into existing code bases in addition to authoring it.
If I can ask, why do you preferred subclassing instead of composition? Could 'b' be a member of 'a' instead? Perhaps to access protected members of class b otherwise inaccessible? In another part of your thread you say inerithance is public just because of a limitation in MS compiler, so your intention would be to use private inerithance, so you don't think at 'a' as is 'b' but in is implemented in terms of 'b', is this correct? Thanks Marco

Marco wrote:
If I can ask, why do you preferred subclassing instead of composition? Could 'b' be a member of 'a' instead? Perhaps to access protected members of class b otherwise inaccessible? In another part of your thread you say inerithance is public just because of a limitation in MS compiler, so your intention would be to use private inerithance, so you don't think at 'a' as is 'b' but in is implemented in terms of 'b', is this correct?
This is the kind of question I wanted asked. Gyuszi suggested composition early on. I don't really have a good rationale for choosing inheritance over composition. At the time, private inheritance was working fine in gcc 4.2.0 and I was able to make the design pattern using inheritance from the template parameter do everything I wanted. I didn't need to access protected members of b. You are correct that I could have made the design pattern work equally well, perhaps better, using composition instead of inheritance. All that I need is for a to be able to safely cast to b and visa-versa. I specifically made this type of code change easy to make by abstracting away the mechanism for accessing the data, but what benefit would I get from changing the design pattern to use composition instead of inheritance? It just isn't clear to me what it is about inheritance that is objectionable in this case. Perhaps this is a learning opportunity for me. Luke

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Simonson, Lucanus J Sent: Monday, October 08, 2007 12:11 PM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
Marco wrote:
If I can ask, why do you preferred subclassing instead of composition? Could 'b' be a member of 'a' instead? Perhaps to access protected members of class b otherwise inaccessible? In another part of your thread you say inerithance is public just because of a limitation in MS compiler, so your intention would be to use private inerithance, so you don't think at 'a' as is 'b' but in is implemented in terms of 'b', is this correct?
This is the kind of question I wanted asked. Gyuszi suggested composition early on. I don't really have a good rationale for choosing inheritance over composition. At the time, private inheritance was working fine in gcc 4.2.0 and I was able to make the design pattern using inheritance from the template parameter do everything I wanted. I didn't need to access protected members of b. You are correct that I could have made the design pattern work equally well, perhaps better, using composition instead of inheritance. All that I need is for a to be able to safely cast to b and visa-versa. I specifically made this type of code change easy to make by abstracting away the mechanism for accessing the data, but what benefit would I get from changing the design pattern to use composition instead of inheritance? It just isn't clear to me what it is about inheritance that is objectionable in this case. Perhaps this is a learning opportunity for me.
Luke _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
I remember reading somewhere that sometimes inheritance can be a trick produce smaller type than composition in some cases. -- John

John Femiani wrote:
I remember reading somewhere that sometimes inheritance can be a trick produce smaller type than composition in some cases.
In the case that virtual functions are used by both the base and derived class inheritance will not incur the additional overhead of an extra virtual pointer that composition would do. In this case also the reinterpret cast from one to the other would be non-safe. This is not the case in my design pattern since I don't use virtual functions in the classes that derive from the template argument. Luke

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Simonson, Lucanus J Sent: Monday, October 08, 2007 3:49 PM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
John Femiani wrote:
I remember reading somewhere that sometimes inheritance can be a
produce smaller type than composition in some cases.
In the case that virtual functions are used by both the base and derived class inheritance will not incur the additional overhead of an extra virtual pointer that composition would do. In this case also the reinterpret cast from one to the other would be non-safe. This is not the case in my design pattern since I don't use virtual functions in
trick the
classes that derive from the template argument.
Luke _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
I think there is also something about classes with no data members. -- John

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Simonson, Lucanus J Sent: Monday, October 08, 2007 4:17 PM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
John Femiani wrote:
I think there is also something about classes with no data members.
I'm not sure what you are driving at. Perhaps I simply don't know
this
one. Please enlighten me.
Luke _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Simonson, Lucanus J Sent: Monday, October 08, 2007 4:17 PM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
John Femiani wrote:
I think there is also something about classes with no data members.
I'm not sure what you are driving at. Perhaps I simply don't know
this
one. Please enlighten me.
Luke _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
------------ main.cpp ------------------- #include <iostream> using namespace std; struct A {}; struct B {}; struct C {}; struct ABC_composite { A _a; B _b; C _c; A& a() {return _a;} B& b() {return _b;} C& c() {return _c;} }; struct ABC_inheritted : public A, public B, public C { A& a() { return * static_cast<A*>(this);} B& b() { return * static_cast<B*>(this);} C& c() { return * static_cast<C*>(this);} }; int main() { cout << "Composite: " << sizeof(ABC_composite) << endl; cout << "Inheritted: " << sizeof(ABC_inheritted) << endl; return 0; } --------- program output ------------- Composite: 3 Inheritted: 1 ---------------------------------------- I just thought it might have something to do with why you opted for it. -- John

Simonson, Lucanus J wrote:
Marco wrote:
If I can ask, why do you preferred subclassing instead of composition? Could 'b' be a member of 'a' instead? Perhaps to access protected members of class b otherwise inaccessible? In another part of your thread you say inerithance is public just because of a limitation in MS compiler, so your intention would be to use private inerithance, so you don't think at 'a' as is 'b' but in is implemented in terms of 'b', is this correct?
This is the kind of question I wanted asked. Gyuszi suggested composition early on. I don't really have a good rationale for choosing inheritance over composition. At the time, private inheritance was working fine in gcc 4.2.0 and I was able to make the design pattern using inheritance from the template parameter do everything I wanted. I didn't need to access protected members of b. You are correct that I could have made the design pattern work equally well, perhaps better, using composition instead of inheritance. All that I need is for a to be able to safely cast to b and visa-versa. I specifically made this type of code change easy to make by abstracting away the mechanism for accessing the data, but what benefit would I get from changing the design pattern to use composition instead of inheritance? It just isn't clear to me what it is about inheritance that is objectionable in this case. Perhaps this is a learning opportunity for me.
Erm, I do not want to be an antagonist here but, you don't need both inheritance and composition to model concepts. They can be useful tools, sure, but they should not be required for modeling concepts. Take STL, for instance, you have a few concepts for containers and sequences (Forward Container, Random Access Container, Associative Container, to name a few). std::vector, std::list, std::set, etc. are all models of these concepts. Surely, you don't need to do anything (neither inherit nor compose some concept classes) to write these classes or for the third party to write his own. Same is true with points. A model of a point is just a model of a point. It need not inherit from anything nor be composed to get the desired model of the Point concept. If an object satisfies the Point model, then all algorithms that work on points work AS-IS, regardless where the point object came from; out of the box from the library, supplied by third party, user supplied, etc. The key here is: AS-IS. Take GIL, for instance. It has this point concept: http://opensource.adobe.com/gil/html/gildesignguide.html#PointSectionDG Now, as long as I model this concept(*** see below) correctly, I should be able to use my home grown point in my library as a GIL point without doing anything. (*** GIL's point concept is intrusive though in that it requires some member functions. A better strategy would be to use customization points: free functions and metafunctions; whereby allowing legacy classes to be adapted non-intrusively.) In Fusion, a library for working with heterogeneous collections of data (http://tinyurl.com/7ra5g), we use concepts too to model containers and views. I've shown in a previous post that I can adopt any struct to make it usable AS-IS in fusion. Concept wise, a struct is a tuple. Out of the box, boost::tuple, boost::array, boost::pair are all adapted. So, I can write: std::pair<int, short> p(1, 2); fusion::for_each(p, cout << _1); and: boost::tuple<int, short> t(1, 2); fusion::for_each(t, cout << _1); and: boost::array<int, 2> a(1, 2); fusion::for_each(a, cout << _1); without having to wrap p, t and a in some adaptor classes or concept map classes. All adaptation is done non-intrusively. You use p, t and a AS-IS without modification, without wrapping. Customization points take care of the mapping. I could take a legacy point, POINT, and adapt it to fusion. Then, I can write: Legacy::POINT lp(1 ,2); fusion::for_each(lp, cout << _1); or even bi-directional: void PrintPoint(const Legacy::POINT&); // supplied by Legacy fusion::for_each(lp, bind(&PrintPoint, _1)); Again, no fuss with inheritance and composition. It just works. ------------------ Ok, nuff said. I hope I made myself clear. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

<snip>
In Fusion, a library for working with heterogeneous collections of data (http://tinyurl.com/7ra5g), we use concepts too to model containers and views. I've shown in a previous post that I can adopt any struct to make it usable AS-IS in fusion. Concept wise, a struct is a tuple. <snip>
Joel de Guzman
Are the concepts in fusion just part of the documentation & design, or do you have concept-checks hidden somewhere? The copy of Fusion I have does not seem use Boost.Concept or ConceptGCC stuff to check them anywhere. (Sorry if this is beginning to drift off-topic) -- John

Simonson, Lucanus J wrote:
Marco wrote:
If I can ask, why do you preferred subclassing instead of composition? Could 'b' be a member of 'a' instead? Perhaps to access protected members of class b otherwise inaccessible? In another part of your thread you say inerithance is public just because of a limitation in MS compiler, so your intention would be to use private inerithance, so you don't think at 'a' as is 'b' but in is implemented in terms of 'b', is this correct?
This is the kind of question I wanted asked. Gyuszi suggested composition early on. I don't really have a good rationale for choosing inheritance over composition. At the time, private inheritance was working fine in gcc 4.2.0 and I was able to make the design pattern using inheritance from the template parameter do everything I wanted. I didn't need to access protected members of b. You are correct that I could have made the design pattern work equally well, perhaps better, using composition instead of inheritance. All that I need is for a to be able to safely cast to b and visa-versa. I specifically made this type of code change easy to make by abstracting away the mechanism for accessing the data, but what benefit would I get from changing the design pattern to use composition instead of inheritance? It just isn't clear to me what it is about inheritance that is objectionable in this case. Perhaps this is a learning opportunity for me.
Ok I posted something but realized I wasn't answering your question why inheritance (nor composition) is desirable when adapting. Here's a strong case... I have a legacy API with an opaque point type: struct point; // hah! opaque, details hidden // getter API float get_x(point const&); float get_y(point const&); Another example would be STL iterators where a pointer can model a random access iterator. Nope, you can't subclass from a pointer. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel wrote:
Ok I posted something but realized I wasn't answering your question why inheritance (nor composition) is desirable when adapting. Here's a strong case...
I have a legacy API with an opaque point type:
struct point; // hah! opaque, details hidden
// getter API float get_x(point const&); float get_y(point const&);
Another example would be STL iterators where a pointer can model a random access iterator. Nope, you can't subclass from a pointer.
I think we aren't on the same wavelength here. My intention was to allow a user to take their legacy type and pass it into my API (without modifying the implementation of the legacy type) by providing the adaptor ConceptMap that defines the points of customization that I require to use their type in my code and by casting their type to its subtype which I have defined. I still don't see how this is "intrusive" nor what better alternative you have to offer. My application developers were very clear when they gave me the requirements for what they wanted in a library. "If something is conceptually a rectangle I want to be able to use it as a rectangle, regardless of what else it also happens to be or what API it provides to get access to its data." If you have a legacy prism type CPrism and it is conceptually a rectangle with the additional z axis data you can pass it into an API I have defined that expected a rectangle: apiExpectingRectangle(RectangleConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API expecting a prism: apiExpectingPrism (RectangularPrismConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API that is overloaded to expect either a rectangle or a prism: apiExpectingRectangleOrPrism(RectangleConcept<CPrism>::mimic(myCPrism)); apiExpectingRectangleOrPrism(RectangularPrismConcept<CPrism>::mimic(myCP rism)); and get different behaviors out of that api depending on which type you told it to model the data as. The way I'm doing it, you have to be explicit about what type you conceptually want to treat the user type as. Is that overly onerous? I just don't understand the nature of your objection. The fact that there are other ways of achieving a similar effect in C++ doesn't explain to me why I should use them instead of what I chose. So far my experience (and users experience) with the library is that it does exactly what it was designed to do with minimum of fuss, mostly related to compiler errors that confuse users who aren't used to working with templates. Luke

Simonson, Lucanus J wrote:
Joel wrote:
I think we aren't on the same wavelength here. My intention was to allow a user to take their legacy type and pass it into my API (without modifying the implementation of the legacy type) by providing the adaptor ConceptMap that defines the points of customization that I require to use their type in my code and by casting their type to its subtype which I have defined. I still don't see how this is "intrusive" nor what better alternative you have to offer. My application developers were very clear when they gave me the requirements for what they wanted in a library. "If something is conceptually a rectangle I want to be able to use it as a rectangle, regardless of what else it also happens to be or what API it provides to get access to its data."
Ok, another example to clarify my point. Say I have a legacy type for a point defined like this: typedef int64 point; // where the high 32 bits is x and low, the y Now how do I inherit from that?
If you have a legacy prism type CPrism and it is conceptually a rectangle with the additional z axis data you can pass it into an API I have defined that expected a rectangle: apiExpectingRectangle(RectangleConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API expecting a prism: apiExpectingPrism (RectangularPrismConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API that is overloaded to expect either a rectangle or a prism: apiExpectingRectangleOrPrism(RectangleConcept<CPrism>::mimic(myCPrism)); apiExpectingRectangleOrPrism(RectangularPrismConcept<CPrism>::mimic(myCP rism)); and get different behaviors out of that api depending on which type you told it to model the data as.
The way I'm doing it, you have to be explicit about what type you conceptually want to treat the user type as. Is that overly onerous? I just don't understand the nature of your objection. The fact that there are other ways of achieving a similar effect in C++ doesn't explain to me why I should use them instead of what I chose. So far my experience (and users experience) with the library is that it does exactly what it was designed to do with minimum of fuss, mostly related to compiler errors that confuse users who aren't used to working with templates.
All I am saying is that there is a better, more generic way. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel wrote:
Ok, another example to clarify my point. Say I have a legacy type for a point defined like this: typedef int64 point; // where the high 32 bits is x and low, the y Now how do I inherit from that? All I am saying is that there is a better, more generic way.
In this, as in anything, there is a tradeoff. In designing the design pattern I made a lot of tradeoffs with the aim, always, of maximizing user productivity and ease of integration of the library while not sacrificing performance or portability. Inheritance limits what qualifies as a valid data type for a geometry object that is compatible with the design pattern and excludes basic types and pointers/references. If there were a real need to include such it might argue in favor of composition as an alternative but I don't see how it argues against both inheritance and composition. The truth is I could use either or mix and match the two as needed and the API and usage would be identical from the user's point of view. I would probably have to use composition if I wanted to apply the design pattern to something simple like the coordinate data type, or an iterator, though I don't se why I would want to do such a thing. You are saying there is a better, more generic way, but you aren't explaining why it is better, or how the ability to generalize basic types and pointers makes it a good tradeoff to apply it instead. Explain to me how you think I could accomplish the same things with less code, less error prone, clearer and easier to understand. I really do want to improve the library. If you have an improvement to offer, it isn't even enough that I take your word for it, I have to be able to explain why it is an improvement to my users and convince them of it. I tried to explain that non-member, non-friend functions were supposed to be the way to go with the first revision of the library, and they overruled me. In the end I agreed with them that having objects that fully encapsulate the behavior of geometry types is nicer and worth some effort, maybe even make a tradeoff or two to get it. Luke

Simonson, Lucanus J wrote:
Joel wrote:
Ok, another example to clarify my point. Say I have a legacy type for a point defined like this: typedef int64 point; // where the high 32 bits is x and low, the y Now how do I inherit from that? All I am saying is that there is a better, more generic way.
In this, as in anything, there is a tradeoff. In designing the design pattern I made a lot of tradeoffs with the aim, always, of maximizing user productivity and ease of integration of the library while not sacrificing performance or portability. Inheritance limits what qualifies as a valid data type for a geometry object that is compatible with the design pattern and excludes basic types and pointers/references. If there were a real need to include such it might argue in favor of composition as an alternative but I don't see how it argues against both inheritance and composition. The truth is I could use either or mix and match the two as needed and the API and usage would be identical from the user's point of view. I would probably have to use composition if I wanted to apply the design pattern to something simple like the coordinate data type, or an iterator, though I don't se why I would want to do such a thing.
You are saying there is a better, more generic way, but you aren't explaining why it is better, or how the ability to generalize basic types and pointers makes it a good tradeoff to apply it instead. Explain to me how you think I could accomplish the same things with less code, less error prone, clearer and easier to understand. I really do want to improve the library. If you have an improvement to offer, it isn't even enough that I take your word for it, I have to be able to explain why it is an improvement to my users and convince them of it. I tried to explain that non-member, non-friend functions were supposed to be the way to go with the first revision of the library, and they overruled me. In the end I agreed with them that having objects that fully encapsulate the behavior of geometry types is nicer and worth some effort, maybe even make a tradeoff or two to get it.
Hmmm, you guys are the ones proposing GTL to boost, right? Shouldn't you be the ones convincing Boosters why your approach is better (if you think it is)? I've enumerated a couple of flaws with it as a general concept modeling scheme and mentioned a couple of existing libraries (including STL) that use different schemes. There are at least 2 main flaws with it as a general modeling scheme: 1) It is not generic enough. It relies on inheritance, a very tight coupling mechanism, and not all c++ objects can be inherited from. It cannot even model STL's iterator concepts (e.g. pointers). You say that you can use composition instead. Sure! But that too has its flaws. It will require that the object is at least copy constructible and/or assignable. Some objects are inherently or even explicitly not. 2) It is unnecessarily verbose. Consider the fusion examples I presented: std::pair<int, short> p(1, 2); fusion::for_each(p, cout << _1); boost::tuple<int, short> t(1, 2); fusion::for_each(t, cout << _1); boost::array<int, 2> a(1, 2); fusion::for_each(a, cout << _1); Now, if I were to use your modeling scheme, that would end up looking like: std::pair<int, short> p(1, 2); fusion::for_each( ForwardSequenceConcept<std::pair<int, short> >::mimic(p), cout << _1); boost::tuple<int, short> t(1, 2); fusion::for_each( ForwardSequenceConcept<boost::tuple<int, short> >::mimic(t) , cout << _1); boost::array<int, 2> a(1, 2); fusion::for_each( ForwardSequenceConcept<boost::array<int, 2> >::mimic(a) , cout << _1); Sorry, no thanks. To me, it's quite clear which one is better. Don't get me wrong, I am not in any way attempting to convince you to change your library. I'm quite sure that you have a well tested, seasoned, industrial strength library. I wouldn't even get in the way when it eventually gets into boost for review, regardless of this /unique/ modeling scheme. As you say, there are alternate ways to do what you want in C++. Fine! It's ok. What I am airing is my concern that this concept modeling scheme won't hold in the more general case, like say, in the related thread discussing about a Boost Point type. That's where my objection lies. There are better concept modeling schemes that do not exhibit the flaws I mentioned. And the good thing is that these "better" schemes can encompass your scheme, so, no problem. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
I tried to explain that non-member, non-friend functions were supposed to be the way to go with the first revision of the library, and they overruled me. In the end I agreed with them that having objects that fully encapsulate the behavior of geometry types is nicer and worth some effort, maybe even make a tradeoff or two to get it.
Using free functions and ADL can be dangerous since there is always the chance of accidentally picking up a function that means something totally different. Traits don't have this limitation. In some ways this is like creating an adapter as you are doing. The difference is that the adaptation layer operates on any instance of the adapted type rather than on one stored inside it. In Christ, Steven Watanabe

Steven Watanabe wrote:
AMDG
Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
I tried to explain that non-member, non-friend functions were supposed to be the way to go with the first revision of the library, and they overruled me. In the end I agreed with them that having objects that fully encapsulate the behavior of geometry types is nicer and worth some effort, maybe even make a tradeoff or two to get it.
Using free functions and ADL can be dangerous since there is always the chance of accidentally picking up a function that means something totally different.
Yeah ADL is bad.
Traits don't have this limitation. In some ways this is like creating an adapter as you are doing. The difference is that the adaptation layer operates on any instance of the adapted type rather than on one stored inside it.
Traits, however, have the tendency to become "metafunction blobs" that are cumbersome to use in TMP if you don't do it right. There are a couple of ways to get around these problems (both ADL and metafunction blobs). Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Steven Watanabe wrote:
AMDG
Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
I tried to explain that non-member, non-friend functions were supposed to be the way to go with the first revision of the library, and they overruled me. In the end I agreed with them that having objects that fully encapsulate the behavior of geometry types is nicer and worth some effort, maybe even make a tradeoff or two to get it.
Using free functions and ADL can be dangerous since there is always the chance of accidentally picking up a function that means something totally different.
Yeah ADL is bad.
Traits don't have this limitation. In some ways this is like creating an adapter as you are doing. The difference is that the adaptation layer operates on any instance of the adapted type rather than on one stored inside it.
Traits, however, have the tendency to become "metafunction blobs" that are cumbersome to use in TMP if you don't do it right.
There are a couple of ways to get around these problems (both ADL and metafunction blobs).
Anyway... "How Non-Member Functions Improve Encapsulation" -Scott Meyers http://www.ddj.com/cpp/184401197 Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If you have a legacy prism type CPrism and it is conceptually a rectangle with the additional z axis data you can pass it into an API I have defined that expected a rectangle: apiExpectingRectangle(RectangleConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API expecting a prism: apiExpectingPrism (RectangularPrismConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API that is overloaded to expect either a rectangle or a prism: apiExpectingRectangleOrPrism(RectangleConcept<CPrism>::mimic(myCPrism)); apiExpectingRectangleOrPrism(RectangularPrismConcept<CPrism>::mimic(myCP rism)); and get different behaviors out of that api depending on which type you told it to model the data as.
Suppose that I want to write template<class Rectangle, class T> void move_up(Rectangle&, T offset); to modify a rectangle in place. if I need to copy the rectangle this isn't going to work. The alternative is to have some set of metafunctions/traits/free functions that allow one to operate directly on the object. template<class T> struct is_rectangle : boost::mpl::false_ {}; // default is not a rectangle template<class T> struct rectangle_get_x; template<> struct rectangle_get_x<CRect> { typedef unsigned short result_type; result_type operator()(const CRect& rect) const; }; // etc. Now generic functions can operate directly on a CRect without making any copies. Then, apiExpectingRectangleOrPrism can be declared as template<class T> typename boost::enable_if<is_rectangle<T> >::type apiExpectingRectangleOrPrism(const T&); template<class T> typename boost::enable_if<is_prism<T> >::type apiExpectingRectangleOrPrism(const T&); If the type passed to this function is either a rectangle or a prism but not both the call is unambiguous. If the type that you want to pass in is both then you can disambiguate by creating an adapter. template<class T> struct rectangle_adapter { T impl; }; Alternately, and probably better, you can define the real functions using different names and have the generic api forward. template<class T> void apiExpectingPrism(const T&); template<class T> typename boost::enable_if<is_prism<T> >::type apiExpectingRectangleOrPrism(const T& t) { return(apiExpectingPrism(t)); } // similarly for rectangle In Christ, Steven Watanabe

Steven wrote:
Suppose that I want to write template<class Rectangle, class T> void move_up(Rectangle&, T offset); to modify a rectangle in place. if I need to copy the rectangle this isn't going to work.
You don't need to copy the rectangle. It does work. Inheritance and composition are just syntactical ways that I can view your data as a rectangle of my type in place. The whole point of my design pattern is that you don't need to copy the rectangle. mimic doesn't copy, it returns a reference to your object of the subclass type with a (safe) reinterpret_cast. Luke

Simonson, Lucanus J wrote:
Steven wrote:
Suppose that I want to write template<class Rectangle, class T> void move_up(Rectangle&, T offset); to modify a rectangle in place. if I need to copy the rectangle this isn't going to work.
You don't need to copy the rectangle. It does work. Inheritance and composition are just syntactical ways that I can view your data as a rectangle of my type in place. The whole point of my design pattern is that you don't need to copy the rectangle. mimic doesn't copy, it returns a reference to your object of the subclass type with a (safe) reinterpret_cast.
Pendantically speaking, there is no such thing as a "safe reinterpret_cast". While this is somewhat permmited in production code where the typical deadline is yesterday, here in boost you need a definite need for using that. Anyway, can you explain in some detail how doesn't your adaptation pattern avoid copying? Best -- Fernando Cacciola SciSoft http://fcacciola.50webs.com

Fernando Cacciola wrote:
Pendantically speaking, there is no such thing as a "safe reinterpret_cast". While this is somewhat permmited in production code where the typical deadline is yesterday, here in boost you need a definite need for using
that. Anyway, can you explain in some detail how doesn't your adaptation pattern avoid copying?
The ability to modify the contents of an object in place without copying was the original intent of the entire exercise in generic programming. If you have two classes class A {...}; class B : public A {...}; or by composition class A {...}; class B { A a; }; You know it is safe to reinterpret_cast A to B and B to A (because they are the same data, and differ in behavior only.) You can take an object of type A, cast it to B, use the behaviors of B to modify it *in place* and cast it back to an A if you like. I don't believe that reinterpret_cast shouldn't be permitted. There are cases where reading the C++ standard will inform a developer that reinterpret_cast is safe and if the compiler causes a problem it is because of a problem in the compiler, not the code. Specifically, I submit that inheritance and composition are such cases provided that additional data members are not added in the subtype or composed type. I don't make the user reinterpret_cast for themselves, but instead provide mimic() and yield() functions for casting to and from my Concept type. If this use of reinterpret_cast to change the behavior of an object is unacceptable for a boost submission that pretty much closes the whole case, since the design pattern depends upon it in a very necessary way. Obviously, we should sort this issue out. There was once an experiment on group learning conducted on monkeys. A group of monkeys in a cage had an electrified banana lowered into it periodically. They quickly learned not to touch it. When new monkeys were introduced into the cage the other monkeys went to extreme measures to prevent them from touching the electric banana. Old monkeys were removed and new monkeys added until eventually no monkey present had ever touched or seen another monkey touch the banana, but still they prevented any new monkey from breaking the taboo. At that point it became impossible for the monkeys to ever learn that the banana was safe, because even if they touched it and didn't get shocked they wouldn't know that the circumstance had changed. Luke

From: Simonson, Lucanus J
Fernando Cacciola wrote:
Pendantically speaking, there is no such thing as a "safe reinterpret_cast". While this is somewhat permmited in production code where the typical deadline is yesterday, here in boost you need a definite need for using
that. Anyway, can you explain in some detail how doesn't your adaptation pattern avoid copying?
The ability to modify the contents of an object in place without copying was the original intent of the entire exercise in generic programming.
If you have two classes
class A {...}; class B : public A {...};
or by composition
class A {...}; class B { A a; };
You know it is safe to reinterpret_cast A to B and B to A (because they are the same data, and differ in behavior only.)
No. 5.2.10 [expr.reinterpret.cast] p7 of the standard says "A pointer to an object can be explicitly converted to a pointer to an object of different type ... the result of such a pointer conversion is unspecified." Notes: - I have snipped the bit where it says you can sometimes cast to a different pointer and back. - Casts between references are defined in terms of casts between pointers. If A is POD, 9.2 [class.mem] p17 guarantees that you can reinterpret_cast B* to A* (but /not/ visa-versa). If B were extended in such a way as to be non-POD, then you lose even that guarantee. There is /no/ guarantee that you can reinterpret_cast between pointers to base and derived class. (static/dynamic cast is different. But even then you can't cast an A* to B* if the A* doesn't point at the A base object of a B) It may work as you expect on the platforms you have used with the types you have used - but it is not guaranteed by the standard.
If this use of reinterpret_cast to change the behavior of an object is unacceptable for a boost submission that pretty much closes the whole case, since the design pattern depends upon it in a very necessary way.
I don't think it is /absolutely/ unacceptable, but I think you would be fighting an uphill battle. I also think you would need to show that you understood the limitations (both according to the standard, and in practise). -- Martin Bonner Senior Software Engineer/Team Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

From: Simonson, Lucanus J
There are cases where reading the C++ standard will inform a developer that reinterpret_cast is safe [snip]. Specifically, I submit that inheritance and composition are such cases
As I said in my previous email, I don't think so. BUT...
provided that additional data members are not added in the subtype or composed type.
... I missed this. I still don't think the standard makes the guarantees you think it does, but in practise, you are much less likely to run into problems with that limitation. If the types are inherited (rather than composed) I still think you have problems if the derived class overrides virtuals in the base. -- Martin Bonner Senior Software Engineer/Team Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

AMDG Martin Bonner <Martin.Bonner <at> pi-shurlok.com> writes:
From: Simonson, Lucanus J
There are cases where reading the C++ standard will inform a developer that reinterpret_cast is safe [snip]. Specifically, I submit that inheritance and composition are such cases
As I said in my previous email, I don't think so. BUT...
provided that additional data members are not added in the subtype or composed type.
... I missed this.
I still don't think the standard makes the guarantees you think it does, but in practise, you are much less likely to run into problems with that limitation.
If the types are inherited (rather than composed) I still think you have problems if the derived class overrides virtuals in the base.
Even without overriding virtuals, technically such a cast is wrong. "If a nonstatic member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined." (9.3.1/1) In other words, you can do the reinterpret_cast to and from the derived class, and that is guaranteed to work, but you cannot call a member function and cast the this pointer back to the base. While what you are doing will probably work I can imagine a case where the compiler helpfully inserts code for detecting such a cast (Since for non-aggregates the compiler is permitted to add extra hidden members) In Christ, Steven Watanabe

Steven wrote:
Even without overriding virtuals, technically such a cast is wrong. "If a nonstatic member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined." (9.3.1/1)
Ah, I see, because I am calling functions of the derived type on an object of the base type you believe that the behavior is undefined. This would be true if the derived type added data members or virtual pointer. In fact, I really struggled with the compiler's stubborn refusal to treat the derived type and the base type as equivalent when designing and implementing the design pattern. It really made me wish for features in that language that don't exist...yet. If I used composition, I would call a function of my composed type on an object of type X (by reinterpret_cast) and it also appears that the standard states that the behavior is undefined based upon your citation. This doesn't convince me that it isn't safe, just that it might not be safe, which we already knew.
reinterpret_cast at least guarantees reversibility, static_cast doesn't even do that. static_cast: "If the rvalue of type "pointer to cv1 B" points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined." (5.2.9/8)
My main issue is that you are relying on unspecified and/or undefined behavior to accomplish this. One possible solution is to store a
rather than a copy. This is problematic when you need a temporary
because you would need two types--one that stores a pointer and one
Yes, if the derived class adds virtual function pointer not present in the base class, or uses multiple inheritance its pointer value may differ from the address of the base class data enclosed within it. I think it is safe to say that we understand this fact and can design around it. Do you know of any other way the pointer values may be different? pointer though, that
can hold a value.
I don't for a minute believe that the behavior I am relying upon is unspecified or undefined. It is specified in the compiler, and all the compilers somehow managed to agree on the definition and specify it the same way. I would be quite surprised if it wasn't the standard that led to this remarkable standardization of C++ compiler front-ends. Perhaps the burden of proof falls upon me, but I don't think I should be considered wrong until proven right. The code works and is perfectly portable. I must have known something when I was designing it. Yes, almost any other solution for doing what I'm trying to do is problematic. It was very problematic to coax the compiler and language to do what I wanted them to. Translating the idea into legal syntax was quite challenging. Luke

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
Yes, if the derived class adds virtual function pointer not present in the base class, or uses multiple inheritance its pointer value may differ from the address of the base class data enclosed within it. I think it is safe to say that we understand this fact and can design around it. Do you know of any other way the pointer values may be different?
The pointers being different is not the only possible problem. Consider the following: struct base { int x; }; class derived : public base { void modify() { x = 1; } }; base b; void foo(derived* d) { d->modify(); b->x = 2; } void bar() { foo(static_cast<derived*>(&b)); } The compiler may see that a member function of derived is being called with the pointer. Thus the pointer must really point to an object of the type derived. Thus it cannot point to b. Knowing that, the compiler is free to reorder the operations after inlining. void foo(derived* d) { b->x = 2; d->x = 1; }
I don't for a minute believe that the behavior I am relying upon is unspecified or undefined. It is specified in the compiler, and all the compilers somehow managed to agree on the definition and specify it the same way. I would be quite surprised if it wasn't the standard that led to this remarkable standardization of C++ compiler front-ends.
I do not think this a good test. The reason this works or appears to work consistently is that this is the default behavior if the compiler does nothing special. In Christ, Steven Watanabe

Steven wrote:
The compiler may see that a member function of derived is being called with the pointer. Thus the pointer must really point to an object of the type derived. Thus it cannot point to b. Knowing that, the compiler is free to reorder the operations after inlining.
No way. The compiler doesn't reorder instructions from before and after an out of line function call because the compiler authors know that they can't guarantee correct behavior for exactly these types of reasons. If the function call is inline the compiler knows whether the pointer is the same or not and if it does not know it does not reorder the instructions because it *might* be the same. In the back-end the compiler doesn't have any idea what object type the pointer was anymore and certainly doesn't use that information to outsmart itself. The compiler is pessimistic and conservative in nature in the optimizations it makes. If compiler providers chose to do what you suggest they might then they would catch no end of grief until they rolled back the change. Luke

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If the function call is inline the compiler knows whether the pointer is the same or not and if it does not know it does not reorder the instructions because it *might* be the same.
What I'm saying is that compiler "knows" that the two pointers are not the same because if they are the same you have undefined behavior anyway so it's not non-conformant if it does something strange.
In the back-end the compiler doesn't have any idea what object type the pointer was anymore and certainly doesn't use that information to outsmart itself. The compiler is pessimistic and conservative in nature in the optimizations it makes. If compiler providers chose to do what you suggest they might then they would catch no end of grief until they rolled back the change.
I remember seeing something related a while back. Ah, here it is. http://lists.boost.org/Archives/boost/2006/10/111792.php In Christ, Steven Watanabe

On 10/11/07, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If the function call is inline the compiler knows whether the pointer is the same or not and if it does not know it does not reorder the instructions because it *might* be the same.
What I'm saying is that compiler "knows" that the two pointers are not the same because if they are the same you have undefined behavior anyway so it's not non-conformant if it does something strange.
Yes, this is very important! There is lots of code around that started breaking when compilers started doing type based alias analysis (practically all code that relied on undefined reinterpret casts which were "practically safe"). Just because it works with current compilers, It doesn't means it won't break with future ones when they'll get smarter and smarter. In the example shown by Steven, if b where declared static or in an anonymous namespace I think that a compiler might reorder even if 'modify' is in another compilation unit if it can prove that the address of b is never taken. And with current link time optimizations technologies, not even an out of line function is a useful optimization barrier.
In the back-end the compiler doesn't have any idea what object type the pointer was anymore and certainly doesn't use that information to outsmart itself. The compiler is pessimistic and conservative in nature in the optimizations it makes. If compiler providers chose to do what you suggest they might then they would catch no end of grief until they rolled back the change.
That might have been true some years ago. Current compilers are pretty aggressive when optimizing and will rely on every dark corner of the specs as possible. And will do more so in the future. gpd

gpd wrote:
Yes, this is very important! There is lots of code around that started breaking when compilers started doing type based alias analysis (practically all code that relied on undefined reinterpret casts which were "practically safe"). Just because it works with current compilers, It doesn't means it won't break with future ones when they'll get smarter and smarter.
That might have been true some years ago. Current compilers are pretty aggressive when optimizing and will rely on every dark corner of the specs as possible. And will do more so in the future.
Well, let's think about this critically. If the compiler started doing optimizations that caused code that casts between base class and derived class and back again to function incorrectly because the compiler decided the spec told it that those were different types and couldn't be the same pointer address what percentage of real C++ applications would be broken? Would it be worse than when the compiler started assuming a pointer to a float couldn't be the same address as a pointer to an int? I pointed out that the banana has no wires coming out of it, yet am being told that we might one day invent wireless transmission of electricity. Even if we did I'm not convinced it would be used to electrify this particular banana. We can always tell the compiler guys "hey, I'm eating this banana, please don't electrify it." Like I said before, if the compiler did what you suggest they would just end up rolling it back because it would break too many things. People are doing egregious things with casting completely unrelated types back and forth all the time. I see it in my work and I do try to tell them they're playing with fire (because it's error prone, not because of compiler concerns) but they can make it work with enough trial and error and that is how real applications work, unfortunately. Luke

On 10/11/07, Simonson, Lucanus J <lucanus.j.simonson@intel.com> wrote:
gpd wrote:
[...] That might have been true some years ago. Current compilers are pretty aggressive when optimizing and will rely on every dark corner of the specs as possible. And will do more so in the future.
Well, let's think about this critically. If the compiler started doing optimizations that caused code that casts between base class and derived class and back again to function incorrectly because the compiler decided the spec told it that those were different types and couldn't be the same pointer address what percentage of real C++ applications would be broken?
A lot. That's why many projects are stuck with obsolete compilers or with suboptimal optimization options.
Would it be worse than when the compiler started assuming a pointer to a float couldn't be the same address as a pointer to an int?
No, it is pretty much the same thing, and it is equally bad.
I pointed out that the banana has no wires coming out of it, yet am being told that we might one day invent wireless transmission of electricity. Even if we did I'm not convinced it would be used to electrify this particular banana. We can always tell the compiler guys "hey, I'm eating this banana, please don't electrify it."
They'll say "Too bad, we told you we could have electrified it sooner or later. You should have listened to us". It has already happened and will happen again. A couple of months ago there where an "interesting" thread on the gcc-devel mailing list about signed int overflow behavior: some application developers argued that optimizing assuming undefined overflow behavior would break lots of applications. The answer they got was pretty much: "then stop relying on undefined behavior!". Sure, they might add an option to disable such an optimization for a while if you ask nice enough, but: - the option won't be there forever. - would you use a library that forces you to a lesser optimization level?
Like I said before, if the compiler did what you suggest they would just end up rolling it back because it would break too many things.
Type based alias analysis is here to stay. I wouldn't be surprised that such code could already break on current compilers given the right circumstances.
People are doing egregious things with casting completely unrelated types back and forth all the time.
It is their application and the can do whatever they like, and they will regret it when their application will break. I do not think we want to consciously introduce these kind of bugs in a boost library. gpd

gpd wrote:
I do not think we want to consciously introduce these kind of bugs in a boost library.
Let's not jump to conclusions before we've thought this through. You are saying that the compiler might assume that a pointer to an object of type A can't possibly be an alias for a pointer of type B, which *inherits* from type A because A and B are different types? That just doesn't make any sense. Obviously A could be an alias for an object of type B, even if the standard says that an object of type A might not be encapsulated within an object of type B and therefore cast from A to B might produce undefined behavior, it doesn't mean that the compiler would ever misconstrue that the mean there is no legitimate circumstance in which a developer would cast an object of type A to B, or B to A, because that is expressly the purpose of subtyping and static_cast. It wouldn't just break non-standard compliant code; it would break all code. Therefore, it is safe to assume that what I'm doing, which currently works, will continue to work in the future. Luke

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
gpd wrote:
I do not think we want to consciously introduce these kind of bugs in a boost library.
Let's not jump to conclusions before we've thought this through. You are saying that the compiler might assume that a pointer to an object of type A can't possibly be an alias for a pointer of type B, which *inherits* from type A because A and B are different types? That just doesn't make any sense. Obviously A could be an alias for an object of type B, even if the standard says that an object of type A might not be encapsulated within an object of type B and therefore cast from A to B might produce undefined behavior, it doesn't mean that the compiler would ever misconstrue that the mean there is no legitimate circumstance in which a developer would cast an object of type A to B, or B to A, because that is expressly the purpose of subtyping and static_cast. It wouldn't just break non-standard compliant code; it would break all code. Therefore, it is safe to assume that what I'm doing, which currently works, will continue to work in the future.
If type A is non-pod and the object of type A is known statically not to be an object of type B, then using the pointer to type B in a way which requires it to really be what it claims to be like calling a non-static member function gives enough information to determine that the to pointers cannot be aliases for each other. If there is sufficient information about the real types of BOTH pointers, then the compiler can assume that they are different. This condition can happen as in the example I gave where the definition of the base class object was visible. In Christ, Steven Watanabe

Simonson, Lucanus J wrote:
People are doing egregious things with casting completely unrelated types back and forth all the time.
Yes, to some still large extent and in spite the effort of the "professional" community to teach otherwise. Is that a blanket-permission to do the same? NO. Our industry sucks, and precisely because of that. There is too many people that should be doing something else... 4 times the last two years I tried to hire a junior developer to absorb part of my workload. Every time I interviewed a candidate I got *so* frustrated that I just gave up for months and just kept working 10 hours a day all by myself. You said it yourself. Boost is supposed to set an example.
I see it in my work and I do try to tell them they're playing with fire (because it's error prone, not because of compiler concerns) but they can make it work with enough trial and error and that is how real applications work, unfortunately.
Yes, but Boost is precisely not limited in the way the industry is. Better take your time and produce something that shows what quality software is about! Anyway, let's not digress. This started becasue you mentioned that you used reinterpret_cast<>, but your are using static_cast<> instead. As long as you don't step over "void*" in the way fom one type to another, static_cast<> is perfectly safe. If you were to screw up the derived class in such a way that it prevents the cast to be 100% safe, the compiler will just reject your code. That's why static_cast<> was invented for. Best Fernando

AMDG Fernando Cacciola <fernando_cacciola <at> hotmail.com> writes:
Anyway, let's not digress. This started becasue you mentioned that you used reinterpret_cast<>, but your are using static_cast<> instead. As long as you don't step over "void*" in the way fom one type to another, static_cast<> is perfectly safe. If you were to screw up the derived class in such a way that it prevents the cast to be 100% safe, the compiler will just reject your code. That's why static_cast<> was invented for.
Yes but casting to a derived sub-object that doesn't exist yields undefined behavior when you attempt to call a non-static member function of the derived class. In Christ, Steven Watanabe

From: Fernando Cacciola
Anyway, let's not digress. This started becasue you mentioned that you used reinterpret_cast<>, but your are using static_cast<> instead. As long as you don't step over "void*" in the way fom one type to another, static_cast<> is perfectly safe.
If you were to screw up the derived class in such a way that it prevents the cast to be 100% safe, the compiler will just reject your code. That's why static_cast<> was invented for.
I don't think that's true. Given: class Base {....} struct Derived : public Base{ int DerivedFunction(); }; Base b; Derived* pDerived = static_cast<Derived*>(&b); pDerived->DerivedFunction(); // Undefined behaviour. The behaviour of the call to DerivedFunction is not defined by the standard. (Of course, on many compilers today it will do what the author expected.) What is more, this is exactly where type aliasing analysis comes in. The compiler knows that b is of type Base, so it knows that it can ignore any changes to memory done through a pointer to Derived when it is optimising.

Martin wrote:
I don't think that's true. Given: class Base {....} struct Derived : public Base{ int DerivedFunction(); };
Base b; Derived* pDerived = static_cast<Derived*>(&b);
pDerived->DerivedFunction(); // Undefined behaviour. The behaviour of the call to DerivedFunction is not defined by the standard. (Of course, on many compilers today it will do what the author >expected.)
The reason it is categorized as undefined is because Derived may extend Base by adding data members, inheriting from another base, or adding a virtual pointer. My contention was that the behavior when none of those conditions is true is defined, or at least implicitly defined. What I mean by implicitly defined is that if X is true, and Y is true then we can infer that Z must also be true. This happens in specs all the time. Steven wrote:
Yes but casting to a derived sub-object that doesn't exist yields undefined behavior when you attempt to call a non-static member function of the derived class.
If I have Base and Derived types the compiler has to ensure correct execution when given the clearly standard compliant usage: Derived object; object.do_something(); Base& baseRef = object; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(baseRef); derivedRef.do_yet_a_third_thing(); ergo it must implicitly support: Base base; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(base); derivedRef.do_yet_a_third_thing(); provided that Derived does not modify Base by multiple inheritance, adding a member or a virtual pointer, because it can't prove that derivedRef is not an alias for the pointer to base because it could be that derivedRef is an alias for baseRef as part of the standard compliant usage. I can make a similar argument for composition based upon the fact that the compiler can't prove statically that a pointer to an object type that is the same type as a data member of another class is not in fact an alias for an object of that other class's type. If a compiler optimization can be proven to break standard compliant code it is safe to assume that such compiler optimization won't happen, or at least will be rolled back immediately. Luke

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If I have Base and Derived types the compiler has to ensure correct execution when given the clearly standard compliant usage:
Derived object; object.do_something(); Base& baseRef = object; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(baseRef); derivedRef.do_yet_a_third_thing();
ergo it must implicitly support:
Base base; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(base); derivedRef.do_yet_a_third_thing();
provided that Derived does not modify Base by multiple inheritance, adding a member or a virtual pointer, because it can't prove that derivedRef is not an alias for the pointer to base because it could be that derivedRef is an alias for baseRef as part of the standard compliant usage.
*Non Sequitur.* Undefined behavior is generally not easily detectable statically. What I've been saying all along is that if do_yet_a_third_thing is a member of Derived then according to the standard if derivedRef is *not* an instance of derived /anything can happen/ In Christ, Steven Watanabe

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
The reason it is categorized as undefined is because Derived may extend Base by adding data members, inheriting from another base, or adding a virtual pointer.
Here are some other things which could break your code: // this is POD struct Base { char c; }; // This is not POD struct Derived : Base { int hidden_variable_added_by_the_compiler; }; Now the alignment of Derived is stricter than that of Base. The standard explicitly states that using a reinterpret_cast from Base to Derived is not guaranteed to be reversible. It also states that the result of a static_cast from Base to Derived is unspecified. Another example // This is POD struct Base { }; class Derived { thread_id_t hidden_variable_added_by_compiler; void f() { // code added by compiler // Try to determine whether the class Derived // may need to be thread safe. Note that more // sophisticated tests are possible, such as checking // whether some mutex is locked. if(hidden_variable_added_by_compiler != get_current_thread_id()) { if(hidden_variable_added_by_compiler == 0) { hidden_variable_added_by_compiler = get_current_thread_id(); } else { add_shared_type(typeid(Derived)); } } //use Base only } }; Now even though f doesn't appear to access any derived class members it really does. In Christ, Steven Watanabe

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
provided that Derived does not modify Base by multiple inheritance, adding a member or a virtual pointer, because it can't prove that derivedRef is not an alias for the pointer to base because it could be that derivedRef is an alias for baseRef as part of the standard compliant usage.
If your argument did hold at all it also holds when Derived contains a virtual pointer. The presence of a virtual pointer does not allow the compiler to prove that derivedRef is not an alias for the pointer to base. Where does that exception come from? The fact that it will obviously not work? Does this mean that we can assume that it doesn't really matter what the standard labels as undefined behavior if we think it will work anyway? What is the point of having a standard then? In Christ, Steven Watanabe

From: Simonson, Lucanus J
Martin wrote:
I don't think that's true. Given: class Base {....} struct Derived : public Base{ int DerivedFunction(); };
Base b; Derived* pDerived = static_cast<Derived*>(&b);
pDerived->DerivedFunction(); // Undefined behaviour. The behaviour of the call to DerivedFunction is not defined by the standard. (Of course, on many compilers today it will do what the author >expected.)
The reason it is categorized as undefined is because Derived may extend Base by adding data members, inheriting from another base, or adding a virtual pointer. Partly My contention was that the behavior when none of those conditions is true is defined, or at least implicitly defined. What I mean by implicitly defined is that if X is true, and Y is true then we can infer that Z must also be true. This happens in specs all the time.
You missed my point about type aliasing. Let's extend the example a little further (and convert to references because that's what you tend to use). struct Base { int i; }; struct Derived : Base { void f() { this->i = 5; } }; Base b; b.i = 2; Derived &refD = static_cast<Derived&>(&b); refD.f(); b.i -= 2; At this point a compiler which does value tracking "knows" that b.i is 2 (not 5) and can optimize the last statement to b.i = 0; With most compilers today, that only works because Derived.f() is inline, and the compiler can see that there is no cast of refD to Base&. Future compilers may be better at optimizing between modules.
If I have Base and Derived types the compiler has to ensure correct execution when given the clearly standard compliant usage:
Derived object; object.do_something(); Base& baseRef = object; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(baseRef); derivedRef.do_yet_a_third_thing();
ergo it must implicitly support:
Base base; base.do_something_else(); Derived& derivedRef = static_cast<Derived&>(base); derivedRef.do_yet_a_third_thing();
provided that Derived does not modify Base by multiple inheritance, adding a member or a virtual pointer, because it can't prove that derivedRef is not an alias for the pointer to base because it could be that derivedRef is an alias for baseRef as part of the standard compliant usage.
Well yes it CAN prove that derivedRef is not an alias for baseRef in your second example - it can /see/ that derivedRef is not an alias for baseRef.
If a compiler optimization can be proven to break standard compliant code it is safe to assume that such compiler optimization won't happen, or at least will be rolled back immediately.
but how about a compiler optimization that /won't/ break standard compliant code, but /will/ break your code? -- Martin Bonner Senior Software Engineer/Team Leader PI SHURLOK LTD Telephone: +44 1223 441434 / 203894 (direct) Fax: +44 1223 203999 Email: martin.bonner@pi-shurlok.com www.pi-shurlok.com disclaimer

Martin wrote:
but how about a compiler optimization that /won't/ break standard compliant code, but /will/ break your code?
I'm tired of reaching my arm down this rat hole. I will let my argument stand on proven portability and comprehensive testing. You (and Steven) can let your argument stand on hypothetical compiler optimizations and snippets of text from the standard. Let's agree to disagree for now and you can bring it up later if you want. Luke

Hi Lucanus,
This doesn't convince me that it isn't safe, just that it might not be safe, which we already knew.
But if something "might not be safe", isn't it almost as bad as being definitely not safe? IOWs, what's the value of safety if it isn't guaranteed?
Yes, if the derived class adds virtual function pointer not present in the base class, or uses multiple inheritance its pointer value may differ from the address of the base class data enclosed within it. I think it is safe to say that we understand this fact and can design around it. Do you know of any other way the pointer values may be different?
But this is the call of the compiler. As long as the standard doesn't force compilers to guarante that a static (witout RTTI) cast from base to derived preserves the pointer value, your presumption is, well, just a presumption.
I don't for a minute believe that the behavior I am relying upon is unspecified or undefined.
It is specified in the compiler ^^^^^^^^^^^^^^^^^^^^^^^^
Exactly! Behaviour specified by the compiler, as opposed to the standard, is called "unspecified", and you shouldn't rely on it unless there is a compelling reason. I still don't see any.
, and all the compilers
...that you have tested it on...
somehow managed to agree on the definition and specify it the same way.
Indeed. This is why if there is a compelling need, you can rely on unspecified behaviour (with the presumption that the actual behaviour matches some reasonable choice, like contiguous allocation of vector elements for instance) (we are not talking about undefined behaviour). But then your are at risk that a new complier/compiler version comes alone and, oh, your library suddenly stops working. I'll give you a concrete example: When VC8.0 was first released we discovered that CGAL was misserably failing, if tested in debug mode, lots of cases that passed with VC7.1 and all other major compilers. When I investigated the issue I discovered the following pattern in the code: Some_iterator null ; Some_iterator get_something() { if ( cant_do_it ) return null ; } Some_iterator result = get_something(); if ( result != null ) use_it(result); VC8.0 crashes in debug mode, yet not in release mode, when that code is executed. Do you see the probem? Simple, a default constructed iterator (like null there) is a singular iterator. And is undefined behaviour to compare two singular iterators. Yes. Even THOSE two singular iterators in spite of the fact that the comparisons involved only copies of the object "null". This pattern was expected to work even in the prescence of a singular internal value for "null" (it could be anything, not neccesarily a null-pointer-value). But no. VC8, in debug mode, purposedly flagged the iterators as singular and refused right up front to compared them, because acording to the standard, is illegal to do that. .. Anyway, I'm loosing focus, so let's rewing a bit... this all started when you explained how you don't need to copy the adaptee. Can you show us in as much detail as possible how do you do that with a very concrete example? Say I have: struct MyPoint { x,y} ; MyPoint p ; and I want to call GTL::foo(p); with the BGL-style of adaptation I write exactly that line (this is what Joel means when he says that you can pass user types AS-IS). What would I need to do in GTL? And, MORE importantly, what does GTL do, exactly, to adapt my "p" objet there? Best Fernando Cacciola

Fernando Cacciola wrote:
Can you show us in as much detail as possible how do you do that with a very concrete example?
Say I have:
struct MyPoint { x,y} ;
MyPoint p ;
and I want to call
GTL::foo(p);
with the BGL-style of adaptation I write exactly that line (this is what Joel means when he says that you can pass user types AS-IS).
What would I need to do in GTL?
And, MORE importantly, what does GTL do, exactly, to adapt my "p" objet there?
You would do write an interface specialization for MyPoint My syntax is not exact, just writing from memory: #include <Gtl.h> template <> class gtl::PointInterface<MyPoint> { pointSet() { ... }; pointGet() {....}; pointConstruct() { ... }; }; then you would typedef: typedef gtl::PointImpl<MyPoint> Point; // and from here on you're set to use the full GTL on MyPoint Point p1(..), p2(..), p3(..); p1 == p2; double d = p1.euclidieanDistance(p2.transform(t) - p3); (p1 += (p2 - p3).set(HORIZONTAL, p2.get(HORIZONTAL) + p3.get(VERTICAL))).toward(p3); etc. Gyuszi

Hi Gyuszi,
My syntax is not exact, just writing from memory:
I'm trying to correlate this with Lucanus post....
class gtl::PointInterface<MyPoint>
This would be the PointConcept in Lucanus post?
then you would typedef: typedef gtl::PointImpl<MyPoint> Point;
With PointImp there you meant PointInterface??
Point p1(..), p2(..), p3(..);
This can't be right. You are constructing an instance of class Point. Where is the adaptation from my instance of type MyPoint? How doesn't this avoid copying? Best Fernando

Fernando wrote:
What would I need to do in GTL? And, MORE importantly, what does GTL do, exactly, to adapt my "p" objet there?
Just typing off the top of my head. I am not yet allowed to copy and paste the code I wrote which Intel owns. typedef int Unit; struct MyPoint {int x, int y}; template <> class PointConceptMap<MyPoint> { public: static inline Unit PointGet(const MyPoint& t, Orientation2D orient) { return orient == HORIZONTAL ? t.x: t.y; } static inline void PointSet(MyPoint& t, Orientation2D orient, Unit value) { if(orient == HORIZONTAL) t.x = value; else t.y = value; } static inline MyPoint PointConstruct(Unit x, Unit y) { MyPoint tmp; tmp.x = x; tmp.y = y; return tmp; } private: PointConceptMap(); //construction disallowed } template <class T> class PointConcept : public T { public: static inline PointConcept& mimic(T& t) { return static_cast<PointConcept&>(t); } static inline const PointConcept& mimicConst(T& t) { return static_cast<const PointConcept&>(t); } inline T& yield() { return *this; } inline const T& yieldConst() { return *this; } inline PointConcept() {} template <class T2> inline PointConcept& operator=(PointConcept<T2>& that) { set(HORIZONTAL, that.get(HORIZONTAL); return set(VERTICAL, that.get(VERTICAL); } Unit get(Orientation2D orient) const { return get_(orient); } PointConcept& set(Orientation2D orient, Unit value) { set_(orient, value); return *this; } private: inline Unit get_(Orientation2D orient) const { return PointConceptMap<T>::PointGet(yieldConst(), orient); } inline void set_(Orientation2D orient, Unit value) { PointConceptMap<T>::PointSet(yield(), orient, value); } static inline T construct_(Unit x, Unit y) { return PointConceptMap<T>::PointConstruct(x, y); } }; template <class T> void foo(T& t) { PointConcept<T>& tref = PointConcept<T>::mimic(t); tref.set(HORIZONTAL, tref.get(VERTICAL); } That is the complete design pattern. It probably has syntax errors because I was typing off the top of my head, but you should get the idea quite clearly. Luke

Hi Lucanus,
Just typing off the top of my head. I am not yet allowed to copy and paste the code I wrote which Intel owns.
typedef int Unit;
struct MyPoint {int x, int y};
template <> class PointConceptMap<MyPoint> { public: static inline Unit PointGet(const MyPoint& t, Orientation2D orient) { return orient == HORIZONTAL ? t.x: t.y; }
First note. These are static member functions, so they are equivalent to non member functions. Well, almost. Template function calls performs template argument deduction, while template class instantiation does not. T use this concept map, a user is required to specify not ony the class name but also the type: PointConceptMap<MyPoint>::PointGet(p,HORIZONTAL); But if the interface used a free template function; template<class PointConcept> typename PointTraits<PointConcept>::CoordType PointGet( PointConcept const& p, Orientation2D orient ) { return orient == HORIZONTAL ? p.x: p.y; } then I could just call: PointGet(p,HORIZONTAL); which is arguably much better to a user. Do *I*, the user, need to implement PointConceptMap and PointConcept?
template <class T> class PointConcept : public T { public: static inline PointConcept& mimic(T& t) { return static_cast<PointConcept&>(t); }
So. PointConcept& adapted_actual_data_ref = PointConcept<MyPoint>::mimic(actual_data); is the way to introduce an instance of the adapter without copying actual_data. OK, at least now I see how do you avoid copying. Second note: This PointConcept class IS NOT a concept, is an adapter. At the very least it should not be called concept. That is, in C++0x I won't be able to replace the definition with something like template <class T> concept PointConcept : .... The reason is that the "role" if this design element is not to enforce that types(s) meets certain requirements but to adapt one very specific other type to meet them. In concept jargon, this is a *model*, not a concept.
inline PointConcept() {}
template <class T2> inline PointConcept& operator=(PointConcept<T2>& that) { set(HORIZONTAL, that.get(HORIZONTAL); return set(VERTICAL, that.get(VERTICAL); }
Unit get(Orientation2D orient) const { return get_(orient); } PointConcept& set(Orientation2D orient, Unit value) { set_(orient, value); return *this; }
Nitpicking here, but, why is set() forwarding to set_() instead of doing this itself?
template <class T> void foo(T& t) { PointConcept<T>& tref = PointConcept<T>::mimic(t); tref.set(HORIZONTAL, tref.get(VERTICAL); }
OK, so at the very least I can pass my point object as-is. In some code posted my Gyuzsi (I think) the user itself was explicitely wrapping at the point of call. OK, you showed us how the pattern works. So, as a user I need to implement PointConceptMap<> and PointConcept<>, is that right? That seems like a lot of unnecesary work to me just to call a library. So, let me start with a concrete review now that I see some actual stuff. Why do I need to implement both PointConceptMap and PointConcept?? Couldn't foo() be implemented like this instead? template <class T> void foo(T& t) { PointConceptMap<T>::PointSet(t ,HORIZONTAL ,PointConceptMap<T>::PointGet(t,VERTICAL) } That cuts down the adaptation burden on my side by half. It even gets rid of the uggliest half (the one with the upcast). Add to that what I said about using free functions to leverage template argument deduction and you get: template <class T> void foo(T& t) { PointSet(t,HORIZONTAL,PointGet(t,VERTICAL); } Best Fernando

Fernando wrote:
Nitpicking here, but, why is set() forwarding to set_() instead of doing this itself?
It has to do with maintainability. You see, I can easily change the design pattern because it is abstracted away from its usage. Only private functions of the PointConcept call the PointConceptMap functions, and I group those private functions together at the end of the class definition. Public functions only call the private functions or eachother and don't need to be changed if the design pattern or PointConceptMap implementation changes.
OK, you showed us how the pattern works. So, as a user I need to implement PointConceptMap<> and PointConcept<>, is that right? That seems like a lot of unnecesary work to me just to call a library. So, let me start with a concrete review now that I see some actual stuff. Why do I need to implement both PointConceptMap and PointConcept??
You don't, that is the point of the pattern. I implement PointConcept once for all points and the user only needs to implement the PointConceptMap for their type. My real PointConcept class has at least a hundred member functions plus stream operators. The PointConceptMap, in constrast, has only three functions. The idea is that the PointConcept gives a gratuitous, rich, and highly productive API, factoring out everything a person might do with a point or pair of points and providing those things as member functions. The PointConcept is the library, as far as points go.
Couldn't foo() be implemented like this instead? template <class T> void foo(T& t) { PointConceptMap<T>::PointSet(t ,HORIZONTAL ,PointConceptMap<T>::PointGet(t,VERTICAL) }
Of course, but then I would need to reimplement foo if I changed the interface. The way I do it I abstract the details of the concept map away from the implementation of functions that use it through the concept class.
That cuts down the adaptation burden on my side by half. It even gets rid >of the uggliest half (the one with the upcast). Add to that what I said about using free functions to leverage template
argument deduction and you get: template <class T> void foo(T& t) { PointSet(t,HORIZONTAL,PointGet(t,VERTICAL); }
Yes, that is pretty much the starting point for generic programming. I started there and added classes, abstractions and indirection until I came up with what I showed you. You can easily argue that I didn't *need* to do anything different from the simple, well know generic programming techniques. There are a hundred different ways to skin a cat. What we should be arguing about is whether what I'm getting for my trouble is worth it. Luke

Hi Lucanus,
Fernando wrote:
Nitpicking here, but, why is set() forwarding to set_() instead of doing this itself?
It has to do with maintainability. You see, I can easily change the design pattern because it is abstracted away from its usage. Only private functions of the PointConcept call the PointConceptMap functions, and I group those private functions together at the end of the class definition. Public functions only call the private functions or eachother and don't need to be changed if the design pattern or PointConceptMap implementation changes.
But private functions do need to be changed in this case. How is it better to change the *implementation* of private vs public functions? Is not that the private functions are out of line in a library. I would understand it if the private functions did not match the interface of the public ones... but doing it the way you did it is IMO over-engineering. It's a good idea to boil down to private method(s) to implement a public one, but not if ALL you do is forward all the work to a SINGLEe INLINE private function that takes exactly the same parameters.
OK, you showed us how the pattern works. So, as a user I need to implement PointConceptMap<> and PointConcept<>, is that right? That seems like a lot of unnecesary work to me just to call a library. So, let me start with a concrete review now that I see some actual stuff. Why do I need to implement both PointConceptMap and PointConcept??
You don't, that is the point of the pattern. I implement PointConcept once for all points and the user only needs to implement the PointConceptMap for their type. My real PointConcept class has at least a hundred member functions plus stream operators.
Ha OK. Yes, this is an important detail. So PointConcept is provided by the library and the user just exposes the map.
The PointConceptMap, in constrast, has only three functions. The idea is that the PointConcept gives a gratuitous, rich, and highly productive API, factoring out everything a person might do with a point or pair of points and providing those things as member functions.
Right. We all agree that the library needs to provide a rich high level API on top of just a few fundamental operations provided by the user.
The PointConcept is the library, as far as points go.
Couldn't foo() be implemented like this instead? template <class T> void foo(T& t) { PointConceptMap<T>::PointSet(t ,HORIZONTAL ,PointConceptMap<T>::PointGet(t,VERTICAL) }
Of course, but then I would need to reimplement foo if I changed the interface.
If what changed **exactly**? Let's see: What foo() does is to "set the horizontal coordinate of "t" to a value equal to its vertical coordinate" This requires the point type to support set(point,orienation) get(point,orientation) this operations are defined by the point concept. The only different between using the PointConceptMap directly instead of PointConcept, for this example, is in the syntax of those operations. So, considering this specific example: Could I change the adapter functions (the map) such that they don't provide Get or Set? NO. If I did that then MyPoint just couldn't be interfaced with foo a all. But I think you just picked the wrong example to show your point. A point I agree with: it is a good idea to require the user to provide just fundamental operations and let the framework compose the more advanced ones on top of that. But again, you can do just the same with the more conventional BGL-style approach to generic programming. You don't need monolithic classes, unusual casts and duplication (there are 3 sets of get/set functions in your example!) to do it.
template <class T> void foo(T& t) { PointSet(t,HORIZONTAL,PointGet(t,VERTICAL); }
Yes, that is pretty much the starting point for generic programming. I started there and added classes, abstractions and indirection
You are not adding "more" or "better" abstractions just because you added classes As for indirection, I'm not sure what that means,
You can easily argue that I didn't *need* to do anything different from the simple, well know generic programming techniques.
Right, I can easily argue that. And I'm doing it since it seems to me that you have over-engineered the adaptation design. Let's see... Considering *only* that simplistic example (getting and setting coordinates of a point), would you agree that free templates functions are all you need and there isno justification do so anything more complex than that? Assuming, yes... When does something more complex starts being neccesary? A user can supply only fundamental operations (like those in your PointConceptMap) via free functions. And the library can certainly build a richer point-related functionality on top of that, also using free template functions and lightweigth traits. Consider that one upside of free fucntions is that they are the opposite of monolthic. A user I can override any level of the adaptation layer if she wants to, because function matching is resolved at the point of call, so is easy to override any function in your API to better much my legacy type, if I need to.
There are a hundred different ways to skin a cat.
But there are lots of people using way "A" and you come in with *your* way "B" (or should that be "L" ;) I'm OK with innovation, but you do need to show us why B is better. Or at the very least, why isn't it worse. Best Fernando

Fernando,
But there are lots of people using way "A" and you come in with *your* way "B" (or should that be "L" ;) I'm OK with innovation, but you do need to show us why B is better. Or at the very least, why isn't it worse.
If I had the same design goals as you, I would hope we would come up with the same solution: the best solution. If I had the same design goals as you and I come up with a radically different solution and everyone already agrees your solution is the best, I either have to convince everyone mine is best, or admit failure. If I had *different* design goals I would expect my solution to be different and the whole argument about better or worse solution goes out the window and we instead need to figure out if I had the right design goals, are your design goals better than mine and under what circumstances. My design goals in order of importance: #1 Low barrier to adoption a. Ease of integration into legacy geometry type systems b. New users must feel comfortable with the API (implies OO) c. Header file only implementation so that there is no link hassles d. No external dependencies, compiler provided library/STL usage only #2 Application developer productivity for users of my library a. API must be object oriented b. API must be intuitive eg: functions that modify an object are named with a verb functions that return an object are named with a noun functions returning a bool are named with an adjective c. API must not be error prone: correctly manage class invariants to minimize side effects fulfill the implicit contract that the API specifies d. Application code implemented using the library can be minimal in line count clear and self documenting implemented at the highest level of abstraction possible #3 Performance Lots of considerations here, not yet brought up, but believe me you will be giving me some pointed feedback once you see the code. #4 Maintainability Introduce abstraction to decrease coupling and improve modularity Generic programming applied internally and not just at interfaces Aggressive refactoring #5 Portability Must work with all reasonable compilers and OS's in both 64 and 32 bit platforms and 64 and 32 coordinate data. #6 Thread Safe (Implied in part by header file only.) #7 Safe for use before opening brace of main (for my users who didn't listen when I told them not to do that...) Obviously if using boost to its fullest were a design goal instead of avoiding external dependencies I might have done things somewhat differently. Also, because I wanted to ease the adoption of the library by new users and target improving the productivity of my users I chose to follow more traditional monolithic class design style instead of the new free function style and make the amount of work they needed to do to use and understand how to use the library as small as possible. For users that use my built in types there is practically zero learning curve. For users that adapt their own types there is a modest learning curve and minimal implementation effort required to partially specialize the ConceptMap class for each. Because the adaptors are grouped together as static member functions of a class it is very obvious what I expect the user to provide. In short, my goal was to integrate into and extend the legacy geometry type systems of as many legacy applications as possible as quickly as possible with the minimum of effort and complaining from new users so that they could start realizing the performance and developer productivity benefits that my library provides. To do that I had to follow some of the conventions for how geometry type systems are expected to behave, which means no free functions. For me it is well worth it. Luke

Simonson, Lucanus J wrote:
For users that use my built in types there is practically zero learning curve. For users that adapt their own types there is a modest learning curve and minimal implementation effort required to partially specialize the ConceptMap class for each. Because the adaptors are grouped together as static member functions of a class it is very obvious what I expect the user to provide.
In short, my goal was to integrate into and extend the legacy geometry type systems of as many legacy applications as possible as quickly as possible with the minimum of effort and complaining from new users so that they could start realizing the performance and developer productivity benefits that my library provides. To do that I had to follow some of the conventions for how geometry type systems are expected to behave, which means no free functions. For me it is well worth it.
Ok, that's it. The question I really was waiting for an answer is: what is the need for this elaborate dance? Now Luke confirms it: the source of all these complexity is their requirement to use member functions everywhere. Luke mentioned "a gratuitous, rich, and highly productive API "with more than "a hundred member functions plus stream operators" Oh my. That's really gratuitous and not to mention obese. Instead of opting for the tried and true STL style generic programming where we have various classes that are models of various concepts plus a set of algorithms that work on these classes, the author(s) chose to shove all those Point algorithms as member functions in the "ConceptMap". Example: double d = p1.euclidieanDistance(p2.transform(t) - p3); Instead of: double d = euclidieanDistance(p1, transform(p2, t) - p3); which is more STL style. To my understanding, the requirement to use member functions everywhere would indeed call for an elaborate scheme to provide genericity from an adapter class that masquerades as its adaptee since there is really no real proxy mechanism in C++. My response: wake up! We are not in the 80s. The STL style of programming has been with us since the 90s. This is the style of programming that Boost advocates. This style of programming can cater to a diverse set of problems and *CAN* address all your requirements. OO does not imply the dot notation. It's just syntax! I'll be aghast if your programmers are not familiar and have never used STL algorithms. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Lucanus,
b. New users must feel comfortable with the API (implies OO)
Do you write "implies OO" as in "implies member functions"? If so consider that lots of people, specially here, consider that tempate free-functions are just one OO-style. That Meyer's article Joel pointed out explains why.
[goals snipped]
If "implies OO" is not a synonynm for "member functions" then I can come up with a design that meets every single goal listed, to the letter, yet following the conventional BGL-style (which is actually rooted in the STL style... the BGL just improved it) Assuming you disagree, can you show us which goal(s) _need_ the approach you choosed instead of the "functional" one? Unless you consider member functions and "old school" OO-style a goal in it self. Note: your library design in on the edge of not being "generic programming" but merely parametrized old school object-oriented programming. It has some genericity scent since at least you can adapt legacy types, but your insistence on member functions in monolithic classes just pushes the design away from generic-programming toward simple template trickery to have class A "mimic" class B. But past the "mimification" (sorry) is just old-schold OO programming.
Also, because I wanted to ease the adoption of the library by new users and target improving the productivity of my users I chose to follow more traditional monolithic class design style instead of the new free function style
What makes you think this actually eases the adoption by new users? Because is "more traditional"? If it *still* where, you would have a point. But it isn't. The now traditional approach is the STL approach (it's more than a decade old!)
and make the amount of work they needed to do to use and understand how to use the library as small as possible.
For users that use my built in types there is practically zero learning curve. For users that adapt their own types there is a modest learning curve and minimal implementation effort required to partially specialize the ConceptMap class for each. Because the adaptors are grouped together as static member functions of a class it is very obvious what I expect the user to provide.
In short, my goal was to integrate into and extend the legacy geometry type systems of as many legacy applications as possible as quickly as possible with the minimum of effort and complaining from new users so that they could start realizing the performance and developer productivity benefits that my library provides. >
Please notice that the statements above clearly indicate that you are making fundamental design desicions based on the presumption of what style of API is "more natural" to the expected users base. So let me ask you this: is your intention to keep this library mainly targeted to Intel programmers? Or is the main target the C++ community at large now? If you are submmitting to boost then it ought to be the modern C+ users out there which are quite familiar and confortable with STL-style frameworks, perhaps even as much as with "old"-style non-truly-generic APIs.
To do that I had to follow some of the conventions for how geometry type systems are expected to behave, which means no free functions.
Can you explain that? Why and how are geometry type systems expected to use member functions instead of free functions? Fernando

Fernando wrote:
Do you write "implies OO" as in "implies member functions"? If so consider that lots of people, specially here, consider that tempate free-functions are just one OO-style. That Meyer's article Joel pointed out explains why. Yes, I read the Meyer's article and other similar articles encouraging non-member, non-friend functions. I think it is safe to say that my data structures are fully encapsulated through a minimal and sufficient interface, the ConceptMap. In addition to that I add a minimal and sufficient interface between the library functions in the Concept class and the ConceptMap, allowing even the concept map to change without needing to change my library functions. I achieve all the goals Meyer's describes already. If I have achieved the goal already, why should I change the code?
Assuming you disagree, can you show us which goal(s) _need_ the approach >you choosed instead of the "functional" one? Ease of use. Since my design is flexible, robust and has good encapsulation already I have the luxury of allowing myself to provide the "good old fashioned" style of API that my users want. If I made my library completely different from what they used before that would hurt uptake and slow down its penetration rate.
Note: your library design in on the edge of not being "generic programming" but merely parametrized old school object-oriented programming. It has some genericity scent since at least you can adapt legacy types, but your insistence on member functions in monolithic classes just pushes the design away from generic-programming toward simple template trickery to have class A "mimic" class B. But past the "mimification" (sorry) is just old-schold OO programming. No, I use templates throughout to make internals generic to decrease coupling, increase modularity and improve my productivity. In particular the internals of the Booleans scanline algorithms are templated and use iterator semantics at their interfaces. The core algorithms are implemented as free functions in addition to templated parameters and iterator interfaces. The old-schold OO style is just my way of gift wrapping my code and putting a nice bow on it to make it easy for the user the use.
Please notice that the statements above clearly indicate that you are making fundamental design desicions based on the presumption of what style of API is "more natural" to the expected users base. So let me ask you this: is your intention to keep this library mainly targeted to Intel programmers? Or is the main target the C++ community at large now? If you are submmitting to boost then it ought to be the modern C+ users out there which are quite familiar and confortable with STL-style frameworks, perhaps even as much as with "old"-style non-truly-generic APIs.
To be frank, I think the developers at Intel are representative of the C++ community at large. I designed the public API for the lowest common denominator of C++ developer, not the elite. I want everyone to be able to be easily productive with the library immediately. Inside Intel the target user is the common man in a cube hacking away at C++ code, desperate to get off the critical path of a microprocessor project, and as open source it is a university student trying to get a term project or research experiment done by his deadline.
To do that I had to follow some of the conventions for how geometry type systems are expected to behave, which means no free functions. Can you explain that? Why and how are geometry type systems expected to use member functions instead of free functions?
Because the people from whom I collected requirements for the ideal computational geometry library told me that was what they wanted. They also wanted it to be generic. I wanted good encapsulation. I managed to come up with a design that did all of those things. Why would I sacrifice one requirement in order to achieve another in a different way? Luke _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Simonson, Lucanus J wrote:
Fernando wrote:
Do you write "implies OO" as in "implies member functions"? If so consider that lots of people, specially here, consider that tempate free-functions are just one OO-style. That Meyer's article Joel pointed out explains why. Yes, I read the Meyer's article and other similar articles encouraging non-member, non-friend functions. I think it is safe to say that my data structures are fully encapsulated through a minimal and sufficient interface, the ConceptMap. In addition to that I add a minimal and sufficient interface between the library functions in the Concept class and the ConceptMap, allowing even the concept map to change without needing to change my library functions. I achieve all the goals Meyer's describes already. If I have achieved the goal already, why should I change the code?
Are you serious? It's all over the article: opt for free functions whenever possible. In your case, you opt for member functions always. Can you honestly say that a class with 100+ member functions is minimal?
To be frank, I think the developers at Intel are representative of the C++ community at large. I designed the public API for the lowest common denominator of C++ developer, not the elite. I want everyone to be able to be easily productive with the library immediately. Inside Intel the target user is the common man in a cube hacking away at C++ code, desperate to get off the critical path of a microprocessor project, and as open source it is a university student trying to get a term project or research experiment done by his deadline.
Again, I ask, aren't they familiar with STL and in particular STL algorithms? STL algorithms are free functions. There's nothing difficult or scary about free functions. It's just syntax. If they are not familiar with STL algorithms as you imply, I'd say, as C++ programmers, they better be. To be honest, I think you are underestimating the C++ community at large if you think that Intel is a representative of it.
To do that I had to follow some of the conventions for how geometry type systems are expected to behave, which means no free functions. Can you explain that? Why and how are geometry type systems expected to use member functions instead of free functions?
Because the people from whom I collected requirements for the ideal computational geometry library told me that was what they wanted. They also wanted it to be generic. I wanted good encapsulation. I managed to come up with a design that did all of those things. Why would I sacrifice one requirement in order to achieve another in a different way?
Because there's a better way. And, IMO, it is our duty, as knowledgable C++ folks, to educate the "lowest common denominator of C++ developer", not to introduce various unsafe reinterpret_casts or static_casts, just to satisfy a certain syntax style and certainly not to advocate fat class interfaces. Ok, I'm through with this thread. Let me end it with this with a quote from Scott Meyers's article: "It's time to abandon the traditional, but inaccurate, ideas of what it means to be object-oriented. Are you a true encapsulation believer? If so, I know you'll embrace non-friend non-member functions with the fervor they deserve." Think STL! Think STL algorithms! :-) Regards -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

I still don't think the standard makes the guarantees you think it does, but in practise, you are much less likely to run into problems with
Martin wrote: that
limitation.
In practice, I have ported it to icc, gcc and visual studio, linux and windows operating systems, x86 and itanium instruction sets, 32 and 64 bit platforms. I am tempted to think that demonstrating portability should count for more than a theoretical argument about what the standard says or doesn't say. I've asked Gyuszi to weigh in on this issue, since his knowledge of C++ exceeds mine.
If the types are inherited (rather than composed) I still think you have problems if the derived class overrides virtuals in the base.
You are correct, and I am impressed by your knowledge, since I learned this one the hard way. I was syntactically unable to override the base class virtual declaration of an assignment operator because it was incorrectly returning void: virtual void operator=(const UglyPolygon &poly); The problem was that the overriding function differed only by return type, which was a problem only because the function being overridden was virtual, despite the fact that the function overriding it was non-virtual. The error the compiler gave was rather cryptic, but I eventually resolved it by removing the assignment operator in the derived class that accepts the base class type as the rvalue. Switching to composition might be preferable to prevent these problems and give me the effect of private inheritance, working around the Microsoft compiler's shortcoming. Luke

Hi Lucanus,
There are cases where reading the C++ standard will inform a developer that reinterpret_cast is safe [snip] Specifically, I submit that inheritance and composition are such cases provided that additional data members are not added in the subtype or composed type.
What *exactly* in the standard supports your claim? Please notice that I am being purposedly pedantic but not to annoy you. My intention is to make a point about why the BGL approach to adaptation (the one Joel has been explaining) is better. I think that your design is based on unspecified behavior, and, given that there are equally valid alternatives, this is unjustified. I could be wrong, so you can show us where in the std is specified that the cast is safe even in this controlled conditions?
I don't make the user reinterpret_cast for themselves, but instead provide mimic() and yield() functions for casting to and from my Concept type.
But the C++ type system doesn't support "mimicing". These functions, by name alone, speak by themselves: they are unusual hacks. (not the mentioned that yield is strongly associated with something different) You said in the presentation that you are submitting this to boost not just because of what is does but because of how it does it, to set an example. Well, given the widely known, well documented and proven adaptation pattern commonly used here in Boost, which is ignificatly different from the one you are proposing, you need to make an unusual effort and convince us that this "mimic" hack is a actually good example.
If this use of reinterpret_cast to change the behavior of an object is unacceptable for a boost submission that pretty much closes the whole case, since the design pattern depends upon it in a very necessary way. Obviously, we should sort this issue out.
What makes it unacceptable, for me at least, is that it is unnecesary. And in fact, it seems that you are aware of that since you mentioned that your first idea was to use free-functions (as the BGL and pretty much every generic library afterwards) but your users managed to convice you that "mimicing" (if I may) was better (what a shame ;)). Keep in mind that submitting a library to boost not always means that the design/code is accepted in the form it was originally created. Sometimes, if not often, acceptance requires a complete re-design and/or re-implementation. But Turst Boost, you can rest assured that such a transformation will be well worth it.
There was once an experiment on group learning conducted on monkeys. A group of monkeys in a cage had an electrified banana lowered into it periodically. They quickly learned not to touch it. When new monkeys were introduced into the cage the other monkeys went to extreme measures to prevent them from touching the electric banana. Old monkeys were removed and new monkeys added until eventually no monkey present had ever touched or seen another monkey touch the banana, but still they prevented any new monkey from breaking the taboo. At that point it became impossible for the monkeys to ever learn that the banana was safe, because even if they touched it and didn't get shocked they wouldn't know that the circumstance had changed.
Precisely... they woudn't know. In fact, they couldn't, as they don't know how to test if the bannana is still eletrified or not. Staying unconditionally away from the banana is the only reliable way for them to avoid damage. That same happens with software, relying on facts that "ought to be true" when we don't really know is risky, and risks are taken only when there is a good reason for it. In your case, I don't see any. Best Fernando Cacciola

I think that your design is based on unspecified behavior, and, given
Fernando wrote: that
there are equally valid alternatives, this is unjustified.
Upon reviewing the code it turns out that I use static_cast in the implementation of mimic. I must have used reinterpret_cast originally and then changed it to static_cast after some code review with Gyuszi. static PointConcept& mimic() { return static_cast<PointConcept&>(t); } I am using autocast on the return value of yield to convert to the base type T& yield() { return *this; } Let's please rewind the conversation. Using composition instead of inheritance would require reinterpret_cast, as I understand it, so perhaps we should decide together if that is really a change I should make. Is the suggestion to use composition a bad idea? Is it based on unspecified behavior?
But the C++ type system doesn't support "mimicing". These functions, by name alone, speak by themselves: they are unusual hacks. (not the mentioned that yield is strongly associated with something different)
Well, given the widely known, well documented and proven adaptation
commonly used here in Boost, which is ignificatly different from the one >you are proposing, you need to make an unusual effort and convince us that
The C++ type system doesn't support it *yet*. I will probably change the name to something more appropriate that relates it to the c++0x proposal for concepts and concept_maps (map_to springs to mind,) doubly so for yield. I was expecting to change the names of just about everything based upon the feedback I get from boost. pattern this
"mimic" hack is a actually good example.
Keep in mind that submitting a library to boost not always means that
Again with the hack. Let's not resort to four letter words. ;) the
design/code is accepted in the form it was originally created. Sometimes, if not often, acceptance requires a complete re-design and/or re-implementation.
That same happens with software, relying on facts that "ought to be
I've had that in mind from the beginning. I am currently considering switching from inheritance to composition, and plan to try that out today to see if it causes any problems. In the end it may be that I to completely transform the library, but if there is nothing left of my original idea because I adopt all of yours, what would be the point of accepting it into boost? It is my hope that there will be some synthesis. If it is just an issue of non-member, non-friend style being in favor now vs. classes with a rich set of member functions I don't think I would ever switch. I am quite clearly encapsulating the data in the data type and using the concept type to organize the set of behaviors the concept is providing for that data. Our use of the language should be based upon an understanding of the benefits and drawbacks of what we are doing, and not simply guided by a pseudo code algorithm from one of Scott's books. true"
when we don't really know is risky, and risks are taken only when there is >a good reason for it. In your case, I don't see any.
Yes, it does happen with software. The point of the anecdote is that we ought to be able to do better than the monkeys. Luke

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
Upon reviewing the code it turns out that I use static_cast in the implementation of mimic. I must have used reinterpret_cast originally and then changed it to static_cast after some code review with Gyuszi. static PointConcept& mimic() { return static_cast<PointConcept&>(t); } I am using autocast on the return value of yield to convert to the base type T& yield() { return *this; } Let's please rewind the conversation.
Using composition instead of inheritance would require reinterpret_cast, as I understand it, so perhaps we should decide together if that is really a change I should make. Is the suggestion to use composition a bad idea? Is it based on unspecified behavior?
reinterpret_cast at least guarantees reversibility, static_cast doesn't even do that. Compare. static_cast: "If the rvalue of type “pointer to cv1 B” points to a B that is actually a sub-object of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined." (5.2.9/8) reinterpret_cast: "Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified." (5.2.10/7) In Christ, Steven Watanabe

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If it is just an issue of non-member, non-friend style being in favor now vs. classes with a rich set of member functions I don't think I would ever switch. I am quite clearly encapsulating the data in the data type and using the concept type to organize the set of behaviors the concept is providing for that data. Our use of the language should be based upon an understanding of the benefits and drawbacks of what we are doing, and not simply guided by a pseudo code algorithm from one of Scott's books.
My main issue is that you are relying on unspecified and/or undefined behavior to accomplish this. One possible solution is to store a pointer rather than a copy. This is problematic when you need a temporary though, because you would need two types--one that stores a pointer and one that can hold a value. In Christ, Steven Watanabe

AMDG Simonson, Lucanus J <lucanus.j.simonson <at> intel.com> writes:
If you have a legacy prism type CPrism and it is conceptually a rectangle with the additional z axis data you can pass it into an API I have defined that expected a rectangle: apiExpectingRectangle(RectangleConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API expecting a prism: apiExpectingPrism (RectangularPrismConcept<CPrism>::mimic(myCPrism)); Or you can pass it into an API that is overloaded to expect either a rectangle or a prism: apiExpectingRectangleOrPrism(RectangleConcept<CPrism>::mimic(myCPrism)); apiExpectingRectangleOrPrism(RectangularPrismConcept<CPrism>::mimic(myCP rism)); and get different behaviors out of that api depending on which type you told it to model the data as.
This doesn't allow for concept refinement. For example if I have a point concept and a runtime-indexable concept I can't create a runtime-indexable point concept just by combining the two. In Christ, Steven Watanabe

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Simonson, Lucanus J Sent: Sunday, October 07, 2007 2:01 PM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
Marco wrote:
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Yes, though I would add that the intention is to use it with classes b1 through bN of libraries B1 through BN so that the effort of making the library generic is worthwhile. Class a inherits from each of the classes b1 through bN through its template parameter. In this way it is as useful as making class a the common base class of b1 through bN, but is not intrusive and leaves the code of libraries B1 through BN untouched. This inheriting one class from many allows us to unify the disparate semantics of many different types that are conceptually similar. I have found it very useful in my day to day work since I end up being the person integrating my library into existing code bases in addition to authoring it.
Lucanus Simonson _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
So the "concept" is also an "adapter"? Wouldn't it make sense to break things down differently; The concepts should lay down the minimal syntax requirements for your own library. You can then provide any number of adapters to and from any other library in order to satisfy your concepts. Asking your 'concept' to be an adapter seems like it may get confusing. -- John

For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Quoting John Femiani <JOHN.FEMIANI@asu.edu>:
So the "concept" is also an "adapter"?
I think a is more like a ConceptMap (basicaly an adapter to a concept) and it was clear from a previous mail that it was considered like this (the code sample was something like PointConceptMap). I suppose ConceptMap just became Concept during the discution. -- Cédric

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Cédric Venet Sent: Monday, October 08, 2007 2:19 AM To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
For what I can understand you have one class 'b' in B library that you want to use with alghoritms of _both_ A and B library the pattern is:
1 - get the class 'a' subclassing 'b'; class a : b 2 - add to 'a' interfaces to deal with algorithms of library A 3 - implement that interfaces using methods of 'b' and/or functions of library B acting on 'b' 4 - use 'a' with library A using the above interface 5 - use 'a' with library B because base class of 'a' is a 'b' Is this interpretation correct ?
Quoting John Femiani <JOHN.FEMIANI@asu.edu>:
So the "concept" is also an "adapter"?
I think a is more like a ConceptMap (basicaly an adapter to a concept) and it was clear from a previous mail that it was considered like this (the code sample was something like PointConceptMap). I suppose ConceptMap just became Concept during the discution.
-- Cédric
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
[John quickly reviews concept maps] So then is it fair to say that GTL will provide ConceptMap features compatible with current compilers? Is BGL hoping to become Boost.ConceptMap + Boost.Point + Boost.RectilinearRegion ? I saw some code in this thread where concepts were used in assertions -- is supposed to be a GTL version of the concept axioms proposed for c++0x? -- John

John Femiani wrote:
So then is it fair to say that GTL will provide ConceptMap features compatible with current compilers? Is BGL hoping to become Boost.ConceptMap + Boost.Point + Boost.RectilinearRegion ? I saw some code in this thread where concepts were used in assertions -- is supposed >to be a GTL version of the concept axioms proposed for c++0x?
I'm not sure how we might factor out the basic idea of ConceptMap as I applied it to become a stand-alone library. It is a design pattern that I repeat about twelve times in my library, so there is scope to factor it out, I just don't see how that factoring could be done in a useful way. It did occur to me to try to implement compile time concept checking, but in the end I just check everything with runtime unit tests that instantiate the templates and make sure everything is hooked up properly that way. Those were supposed to be runtime asserts you were looking at. Certainly I would like to take things in the direction of showing how the benefits proposed for c++0x proposal for concept_map are available now using traditional templates (enough of them anyway) but I authored the design pattern before becoming aware of the c++0x proposal, so I can't claim that was my intention. It may be that the scope of the proposed submission is too large, or not sufficiently focused. That is something we should be trying to figure out. Luke

John Femiani wrote:
Array access has it own problems; I think we would need to accommodate both.
Yes!
I am not too familiar with fusion; but I have used GIL which has concepts for heterogeneous as well as homogeneous types. The most generic type of access is obtained by something like the get<> template function below (but GIL calls it at_c<>).
Fusion calls it at_c<N> too, FWIW. As do MPL. get<N> is just a synonym for backward compatibility with TR1 tuple. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

John Femiani wrote:
If we want boost to have a point class I think it will really have to be a set of point adapters and point concepts that work for existing types. There are too many points out there that we would have to interact with, both outside of boost and also within boost. For instance it would be nice if algorithms worked with both Boost.Point and the CGAL point.
Exactly my point. Well said! I'd add though that adaptation should be non-intrusive, non-invasive. We should be able to use a point type from library A and library B as-is. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Joel de Guzman Sent: 06 October 2007 00:39 To: boost@lists.boost.org Subject: Re: [boost] [GTL] - geometric template library - determininginterest
John Femiani wrote:
If we want boost to have a point class I think it will really have to be a set of point adapters and point concepts that work for existing types. There are too many points out there that we would have to interact with, both outside of boost and also within boost. For instance it would be nice if algorithms worked with both Boost.Point and the CGAL point.
Exactly my point. Well said! I'd add though that adaptation should be non-intrusive, non-invasive. We should be able to use a point type from library A and library B as-is.
Jake Voytko's GSoC SVG graph plotting library comes immediately to mind as a simple, but very useful, example. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

On 10/4/07, Phil Endecott <spam_from_boost_dev@chezphil.org> wrote:
* Homogeneous vs. heterogeneous coordinate types: for example, in a mapping application, latitude and longitude are (almost) the same type, whereas altitude has an entirely different range and might benefit from using a different type e.g. a different fixed-point scale factor. So do we have one template parameter or n template parameters?
I have code that supports heterogeneous coordinate types in 2D, 3D, and 4D for exactly the example you gave - I do GIS related work. There was a lot of trickery involved to determine appropriate return types for things like: vec3<float, float, short> result = vec3<short, short, short>(1, 2, 3) + vec3<float, float, short>(1.0, 2.0, 3.0); I suspect there are now Boost libraries that will make that easy (or at least easier).
* Fixed or variable number of coordinates: I'm happy with 2d and sometimes 3d points and using distinct types for them, but some people think in higher dimensions and need points with arbitrary numbers of dimensions.
Instead of coding a generic class that supported N dimensions, I made a 2D, 3D, and 4D class. Functions like cross_product and dot_product only worked on certain types, but thinking about it, there's no barrier to making that work with a generalized point class. I did however code a separate quaternion class as I felt it was significantly different than a 4D point. I have no strong opinion on the implementation of this. I do think that it should support Boost.Units though, so I can do something like: vec3<nautical_miles, nautical_miles, feet> radar_range;
* xyz or [n] notation: using .x, .y and .z to access the coordinates seems simpler to me, but the higher-dimension people would prefer to use [0], [1] ... [n]. That notation also has the advantage that you can iterate through the dimensions. Is it possible to support both?
It's possible to support both, either through Fusion, or through a static array of pointers to members. It's also possible to support swizzle notation through functions with some macros that I made last year, e.g. you can do: float4 c = a.xxyy() + b.wwzz();
* Accessors or simple variables: should I write p.x or p.x() or p.get_x() ?
I much prefer p.x and/or p[0].
* Member functions or free functions: p.distance_to(q) or distance_between(p,q) ?
For functions that modify, I prefer member functions: p.normalize(); but I also provide free function versions of all member functions that copy/modify/return, like so: float3 normalize(float3 pt) { return pt.normalize(); } just so that it's easier in client code when that behavior is desired. For functions that do not modify, I prefer free functions: distance_between(p, q); Just my 2 cents... --Michael Fawcett

Simonson, Lucanus J wrote:
There is the strong possibility that I will be extending the GTL capabilities beyond 45 degree to allow arbitrary angles with the goal of providing best in class performance with a generic and productive interface.
Wouldn't this compromise the key facts of rectilinear geometry? You can provide robust operations based solely on fixed-point arithmentic precisely becasue of this restriction (or am I mistaken there?) To support arbitrary angles you need rational coordinates, but then you enter the world of non-rectilinear geometry whose rules are completely different.
As we are all aware, this leads to the need to provide a mechanism to ensure numerical robustness at considerable cost in runtime. That mechanism would obviously include a generic interface for specifying the internal numerical data type to be used by the algorithm, with a default provided by the library.
Is not as simple as that I'm afraid. Not for industrial-strenght code. See for example the CGAL approach to it: http://www.cgal.org/philosophy.html Right now you have a library that can be used in real production, but that's because it exploits the restrictions of its target domain. I suggest to keep it that way.
However, our intention is not to provide a comprehensive geometry library, which would be too broad in scope,
And which needs *different* design decisions.
but rather a starting point for generic geometry that the community can participate in and extend in the most useful directions. In looking at the recent submissions to boost related to geometry there is a fair amount of overlap with our library, particularly in what I call the basic types such as point2d. The ideal outcome from my point of view is that we all benefit from a synthesis of ideas and craft a boost geometry library together that goes beyond the code we will initially submit and will continue to be enhanced and extended with the participation of the community over time.
I agree with your POV. One way do that without compromising the key aspects of your work is to stratify it. That is, factor out the bottom layer than is relevant to most geometric domains and keep the stuff specific to rectilinear geometry in a top layer. The bottom layer would include the point class (and IMO it *should* include a vector class to simplify "directional" operations) The design decisions for the bottom layer need not be the same as those for the top layer (rectilinar geometry) Best -- Fernando Cacciola SciSoft http://fcacciola.50webs.com
participants (17)
-
Cédric Venet
-
Dave Steffen
-
Fernando Cacciola
-
Giovanni Piero Deretta
-
Joel de Guzman
-
John Femiani
-
Marco
-
Marco Costalba
-
Martin Bonner
-
Michael Fawcett
-
Michael Marcin
-
Miles Bader
-
Paul A Bristow
-
Phil Endecott
-
Simonson, Lucanus J
-
Steven Watanabe
-
Suto, Gyuszi