Boost logo

Boost :

Subject: Re: [boost] [geometry] view_as concept casting
From: David Abrahams (dave_at_[hidden])
Date: 2009-01-09 16:21:13


on Fri Jan 09 2009, "Simonson, Lucanus J" <lucanus.j.simonson-AT-intel.com> wrote:

>>refinement:
>>
>> +-- p <------+
>> / \
>> pwh <--+ +-- p45 <---+
>> \ / \
>> +-- p45wh <--+ +-- p90
>> \ /
>> +-- p90wh <--+
>>
>>Ja?
>
> Ja, that's the one that crashed the compiler when I tried to take out
> the virtual keyword.

Which 'piler is this?

> I inherited the tags (not the data types) from each other multiply in
> exactly that manner. I found that more recent version of the compiler
> were able to handle it, of course ;)
>
> This allows any algorithm that would accept a pwh to accept a p90,
> which doesn't work for the lhs of an assign, obviously.
>
>>You gotta straighten out your terminology, man; it muddles the thinking.
>>Tags correspond to concepts.
>
> Ah, I see, I was calling the dispatched to function a dispatch
> function because it is usually named foo_dispatch, whereas you call
> the dispatcher function the dispatch function because it does the
> dispatching.
>
> I implemented the above hierarchy as
> struct pwh{};
> struct p : pwh{};
> struct p45wh : pwh{};
> struct p45 : virtual p, p45wh {};
> struct p90wh : p45wh;
> struct p90 : virtual p45, p90wh {};
> But wasn't keen on a virtual pointer in a tag, so took out virtual keyword.

Yeah, you shouldn't need it.

>>From the what you wrote above and the diagram it looks like the RHS
>>simply has to be a possibly-indirect refinement of the LHS.
>>I'm pretty sure you only need a single dispatch function
>> // dispatch function
>> template <class LhsPoly, class RhsPoly>
>> void assign(LhsPoly& l, RhsPoly const& r)
>> {
>> BOOST_MPL_ASSERT((
>> is_convertible<
>> typename polygon_category<RhsPoly>::type
>> , typename polygon_category<LhsPoly>::type
>> >));
>>
>> assign_impl(l, r, typename polygon_category<LhsPoly>::type());
>> }
>>with at most 6 implementations
>> // for example
>> template <class LhsPoly45, class RhsPoly45>
>> void assign_impl(LhsPoly45& l, RhsPoly45 const& r, p45_tag)
>> {
>> ...
>> }
>>Am I missing something?
>
> I guess not. Like I said, it is easy to write the six functions to work in all cases
> they are supposed to work, but hard to exclude them from working in all the other
> cases they are not type safe. By implementing the in_convertable
> metafunction

That's in boost/type_traits/is_convertible.hpp; I didn't have to
implement it!

> and using it in the assert you exclude those. You could have as
> easily done that around the return type as in the body. Assuming you
> want to overload assign, or allow it to be safely overloaded later you
> would want to guard it with SFINAE anyway. Because my function names
> are very generic I like to avoid collisions. The distance() function
> between two geometry objects collided with std::distance between two
> iterators in gcc 3.2.2 or 3.4.2, for instance (despite being in
> different namespaces) so I had to rename it to euclidean_distance.

Sure, makes sense.

> However, you didn't implement it with tag dispatching alone, you used
> MPL assert, which is equivalent to SFINAE.

If you use SFINAE in the traditional way, you can't take advantage of
any refinement relationships and you need to explicitly exclude all the
other cases. Of course, you could use SFINAE with an is_convertible
test on the tags, which would get around that problem. But I would
still do that on the dispatch function and use tags to select the
implementation.

> If you consider mpl assert to be tag dispatching then you can do it
> with tag dispatching. I considered them to be two different
> techniques.

They are completely different. The dispatching problem, which is what
you said you struggled with, is handled completely by tag dispatching.
The other problem is how to generate errors for the cases you don't want
to allow, and yeah, there are several different possible approaches there.

> I chose SFINAE instead of tag dispatching for my generic
> overloading. It is equivalent, but is it inferior somehow?
>
>>> That helps for reading, but not for writing. You can't assign to a
>>> non-mutable object.
>
>>Yeah, you can ;-)
>>
>>Whole object mutations are okay; it's the partial mutations that may
>>destroy the invariants of a refined concept that get you in trouble. In
>>other words, Rectangle can support assignment but not set_height,
>>because Square's invariants depend on not changing the height without
>>the width.
>
> Ah, terminology again. I don't support partial mutations of polygons
> anyway, though I do for points and rectangles.

Then Rectangles aren't immutable but Polygons are. Odd asymmetry.

>>> Because your mutable objects are leaves they can only assign from
>>> themselves.
>
>>Efficiently? Well, ask yourself this:
>>
>>* how much code did you save over the technique I demonstrated?
>
> None, in fact I have a great deal of code duplication in the SFINAE
> metaprogramming around the return types of my overloads that could be
> factored together into the dispatcher function.

Exactly.

>>
>>* how much simpler is your code than mine?
>
> No simpler.
>
>>* most of all, what happens to your code when you have to integrate a
>>new concept into the system?
>
> In some cases it might take me more code, but in others not. If I add
> triangle to the mix I can specialize is_polygonal and give the
> triangle polygon-read-only traits to work with the existing overloads
> of assign.

You lost me.

> Tag dispatching could help cut down on the number of SFINAE protected
> overloads of functions, which would save some typing, but the number
> of functions in the library would be about the same.

It's not about the number of functions; it's about having to hit a whole
bunch of unrelated implementations when a new concept is introduced, to
make sure they don't match it.

> Right now I have 314 SFINAE overloads of various function names.
> Having to modify all of them to deal with a limitation in the way the
> MS compiler parses SFINAE really is a chore. I'd have only 200 or so
> to do if I implemented things the way you propose, but that is a
> difference in degree, not order of work.

are you arguing that a 35% reduction in the size of your job is
insignificant?

It's your funeral I guess ;-).

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk