|
Boost : |
Subject: Re: [boost] [geometry] view_as concept casting
From: David Abrahams (dave_at_[hidden])
Date: 2009-01-09 14:51:15
on Fri Jan 09 2009, "Simonson, Lucanus J" <lucanus.j.simonson-AT-intel.com> wrote:
>>> You can assign a polygon to a polygon with holes, but not the other
>>> way around. It turns out that roughly half the possible combinations
>>> of types
>>> that could be arguments to assign were legal, meaning I had
>>> O(n^2) assign_dispatch functions to write.
>
> Dave A wrote:
>>I don't see it.
>
> Ok, I have six different polygon tags.
> polygon_90 (rectilinear polygon)
> polygon_90_with_holes
> polygon_45 (extends rectilinear to allow for 45 degree edges)
> polygon_45_with_holes
> polygon
> polygon_with_holes
>
> The API is 100% type safe wrt these six polygon types. Because I have rectilinear, 45
> and arbitrary angle geometry algorithms implemented I need all of these types.
>
> I'll abbreviate them p90, p90wh, p45, p45wh, p and pwh.
refinement:
+-- p <------+
/ \
pwh <--+ +-- p45 <---+
\ / \
+-- p45wh <--+ +-- p90
\ /
+-- p90wh <--+
Ja?
> Legal combinations of assignment are as follows:
> pwh can be assigned to pwh only
> p can be assigned to p and pwh
> p45wh assigns to p45wh and pwh
> p45 assigns to p45, p45wh, p and pwh
> p90wh assigns to p90wh, p45wh and pwh
> p_90 can assign to all six.
>
> That's 18 out of 36 possible combinations are legal. I could just be
> dense, but I couldn't figure out how to do that with tag dispatching
> without writing 18 dispatch functions if each type gets its own unique
> tag.
You gotta straighten out your terminology, man; it muddles the thinking.
Tags correspond to concepts.
>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?
> There was no inheritance tree that gave me those 18 and only those 18,
> and multiple inheritance DAGs didn't improve matters either.
You don't need inheritance other than tag inheritance.
>>I don't see any problems; just tag dispatch based on the concept modeled
>>by the LHS. Assign for Polygons can forego asking about the number of
>>RHS holes, assign for Rectangles can forego asking how many points there
>>are, and assign for Squares can forego asking for one of the side
>>lengths. What am I missing here?
>
> 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.
> Because your mutable objects are leaves they can only assign from
> themselves.
You have to remember that's a refinement (not an inheritance) hierarchy.
boost::function<void()> does not have a direct refinement relationship
with void(*)() and yet you can still assign from the latter into the
former.
> All of my objects would be mutable, leaves in your hierarchy, and not
> inter-compatible.
>
> You are also missing Polygon <-- Polygon45 <-- Polygon90.
You didn't tell me about those, so of course I missed them.
> You don't want to use multiple inheritance (I crashed the compiler
> trying.)
If your compiler can't handle MI, just give up programming now ;-P
>>> We need more than just overloading of generic functions based on
>>> conceptual type to implement a generic geometry library, we need
>>> static polymorphism.
>
>>I'm sorry, but that doesn't make any sense to me. One of the big
>>selling points of GP is that you *don't* lose static polymorphism. You
>>certainly don't lose any type information by tag dispatching.
>
> Ok, I guess I phrased that poorly. Metaprogramming around the return
> type allows us to specify exactly the logic of types we want to allow
> without any of the restrictions of hierarchical organization imposed
> by inheritance. For the above example of six flavors of polygon I
> wrote six overloads of assign() and metaprogramming around the return
> types that allowed me to efficiently implement the type restrictions
> for what is and isn't legal arguments for each overload.
Efficiently? Well, ask yourself this:
* how much code did you save over the technique I demonstrated?
* how much simpler is your code than mine?
* most of all, what happens to your code when you have to integrate a
new concept into the system?
-- 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