Boost logo

Boost :

Subject: Re: [boost] [geometry] view_as concept casting
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2009-01-09 15:54:17


>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. 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.

>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 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.

However, you didn't implement it with tag dispatching alone, you used MPL assert, which is equivalent to SFINAE. 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. 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.

>> 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.

>
>* 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.

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. 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. I readily admit I'd be happy to type less, not least because I typed my fingers so sore switching to SFINAE overloading that I could barely sign my name.
 
Respectfully,
Luke


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