|
Boost : |
From: Fernando Cacciola (fernando_cacciola_at_[hidden])
Date: 2007-10-11 14:35:23
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk