|
Boost : |
From: Mat Marcus (mat-boost_at_[hidden])
Date: 2003-10-06 12:55:43
--On Monday, October 06, 2003 7:36 AM -0400 David Abrahams
<dave_at_[hidden]> wrote:
> The insistence that everything needs to be grouped together is the
> same as insisting that all concept requirements on regular classes
> must be expressed as member functions and not as free functions.
>
> But we've learned the lessons surrounding this issue too many times
> for me to waste any more keystrokes on it. As I mentioned earlier,
> if I haven't convinced you by now, I don't expect I will. If this
> thing ever comes to formal review with the grouped implementation, I
> think you can guess how I'll vote. I'll be satisfied with that as my
> final expression of my opinion about it, and with whatever the
> group's decision may turn out to be.
>
> And now, on to other threads...
I believe that some of the misunderstanding here arises from the fact
that there are certain design principles that implicitly inform some
of the design decisions at boost. Perhaps I think it could be useful
to try to make some of them explicit at this point.
As our understanding of how to write libraries in C++ grows some
programmers are moving beyond classes and objects towards concepts and
models. I will try to mention some of the principles of concept-based
design, especially those that differ from those that guide the more
traditional OOD approach. These ideas are useful for both runtime and
compile time C++ programs. Of course, I do not claim that these ideas
are new. Much of the underlying work was done in the 70's, then in the
STL, and these ideas have been explained by better writers for some
time.
Many of us have been trained in traditional OO techniques, following
Booch, et. al. C++, however is a multi-paradigm language and other
design mechanisms are available. Generic programming has proven to be
a very powerful approach to solving problems. Let me spend a few
moments to consider some of the differences between (generic)
concept-based design (CBD) versus OO design.
Both OOD and CBD are concerned with polymorphism. OOD achieves
polymorphism through inheritance and virtual functions while generic
programming does so via overloading and parametric polymorphism
(e.g. function templates). One key advantage of the generic
programming over OOD is that it is non-intrusive. That is, there is no
requirement that a model of a concept inherit from anything at all
(you could say that models are to concepts in generic programming as
objects are to classes in OOD). This way even built in types can be
models of a concept, e.g. pointers model various iterator concepts and
vectors of lists model graph concepts. Another advantage of generic
programming is that the first parameter (implicit this) is no longer
treated specially. Multiple dispatch is available. Of course sometimes
you really need runtime polymorphism. But I will argue that today many
programmers apply subtype polymorphism to nearly all design problems,
whether or not such runtime variance is needed.
So here are a few principles with some thin justification. I don't
claim that these are perfect or complete. Maybe a bit of discussion
will refine them.
Specify libraries using concepts instead of, say, using abstract base
classes where possible and appropriate. In such cases the following
principles might apply.
Avoid making member functions part of the public API where
possible. Whether or not something is a member function is strictly an
implementation detail. Offer your libs functionality as a collection
of free functions and/or function templates.
Avoid making member data part of your public API. Prefer the get()
idiom.
Avoid nested types. But also avoid traits classes in an attempt to
reify metafunctions. Prefer free metafunctions. We don't need more
fat, closed traits classes anymore then we need more fat closed
classes.
The intent of the three principles above is to allow the widest
possible variety of representations to model a concept. Avoid the
pitfall of overconstraint imposed by OOD. It is important to allow
generic algorithms to be written that don't impose unnecessary
restrictions upon the data types on which they operate.
Of course questions remain. One particular area that needs some more
work is the question of modules/namespaces. I would argue that
reification into classes/objects is undesirable, but some kind of
packaging is needed. This can get rather complicated in the
presence of ADL and the potential unboundedness function
templates. SFINAE/enable_if may be of some help and perhaps techniques
like Brian suggests could be of some use for compile time packaging,
but there remain questions of overhead. I'd be interested to hear what
thoughts others may have had on this subject.
- Mat
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk