C++ design/over desiging : stl style vs OOPS, OOAD

P

persres

Hello,
I am a bit confused about so many design approaches to even the
simplest of problems. I am not able work with all of them together. It
seems I have to pick one of these.

Mainly there seems a distinct choice between the two.
1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc. (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

When do you do what. Can I say that if its a computation/algorithmic
problem we are solving- style 1. If it is one of software design -
style2. Is that true?

For instance, consider a simple problem of designing a data structure
for an n-ary tree of integers. How would you design one if all you
know is you need an n-ary tree?. What interfaces would you
provide.

1. My choice would be to just store the entire tree in a vector.
Access each node by a pair - row, index. Provide an interface to
GetElementAt() and GetChildrenOf() . Simple and enough I should
think. I will not worry about making the underlying implementation
configurable. It will always be vector.

2. Just to iterate there are a myriad of alternatives.

a)Say the iterator pattern. I can design an one say -
CreateIterator()., Next(), to iterate through rows are children.

b) I can create an enumerator. Say row_enumerator->GetNumofElements(),
element_enumerator->GetNumOfChildren(), element_enumerator-
GetChildAtIndex(). I prefer the GetNumOfChildren compared to
CreateIterator()., Next() etc. What do you feel. Any reason why
iterator pattern is better. I wonder why this iterator pattern exists
or is used.


The problem the above two approaches don't get along with stl
algorithms.

c) I implement an iterator that is compatible with stl algorithms.

3. a)Design some policies to configure the underlying implementation.
Is this really worth it?. I really feel this is just going too far and
over designing. Any thoughts?

b) Design policies to configure interfaces. You could do Multiple
inheritance and inherit from a certain class that defines an
interface. This also seems too complicated.

I prefer the stl kind of approach. It seems so different from the old
style oops. What are your thoughts?
 
V

Victor Bazarov

Hello,
I am a bit confused about so many design approaches to even the
simplest of problems. I am not able work with all of them together. It
seems I have to pick one of these.

Mainly there seems a distinct choice between the two.
1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc. (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

When do you do what. Can I say that if its a computation/algorithmic
problem we are solving- style 1. If it is one of software design -
style2. Is that true?
[...]
I prefer the stl kind of approach. It seems so different from the old
style oops. What are your thoughts?

There is a place and time for everything. The Standard Library
mechanisms are there to allow you not to re-implement low-level data
structures and parts of your algorithms. Once you move above your low
level, you're usually faced with higher abstractions that do require OOD
(along with OOA). The approach involving OOA/OOD is essential for
keeping your system extendable. Policies and other generic stuff are
there to help you manage concepts at any level, AIUI.

Have you leafed though the "Multi-paradigm design for C++" by Coplien?
Get a copy and give it a good read, you won't be disappointed. And
don't mind the fact that it's more than 10 years old.

Good luck!

V
 
J

Jorgen Grahn

Hello,
I am a bit confused about so many design approaches to even the
simplest of problems. I am not able work with all of them together. It
seems I have to pick one of these.

Mainly there seems a distinct choice between the two.
1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc. (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

Are you talking about software design in general, or about designing
reusable libraries? Because if you mean the former, there are plenty
of other alternatives, and it's definitely not black and white.

If you have "The C++ Programming Language", I recommend reading the
chapters near the end about design and programming. There's a healthy
dose of pragmatism there which is fairly rare in such texts.

....
For instance, consider a simple problem of designing a data structure
for an n-ary tree of integers. How would you design one if all you
know is you need an n-ary tree?. What interfaces would you
provide.

I have a relaxed attitude to Design, so: it would depend entirely on
what I needed the tree /for/. I wouldn't waste time designing it to
do things which aren't useful to me.
2. Just to iterate there are a myriad of alternatives.

a)Say the iterator pattern. I can design an one say -
CreateIterator()., Next(), to iterate through rows are children.

b) I can create an enumerator. Say row_enumerator->GetNumofElements(),
element_enumerator->GetNumOfChildren(), element_enumerator->
GetChildAtIndex(). I prefer the GetNumOfChildren compared to
CreateIterator()., Next() etc. What do you feel. Any reason why
iterator pattern is better. I wonder why this iterator pattern exists
or is used.

The problem the above two approaches don't get along with stl
algorithms.

I don't understand this. Please explain your motives for considering
any other iterators than normal C++ iterators -- do they come from
the Gang of Four book, or Java, or something?
I prefer the stl kind of approach. It seems so different from the old
style oops. What are your thoughts?

That you'll not find a lot of people here who'll say "C++ is evil, go
design your application as if it was Smalltalk!"

/Jorgen
 
N

Nobody

1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc. (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

When do you do what.

With #1, you write one chunk of source code, and the compiler generates a
new chunk of object code for each set of template parameters which occurs.

With #2, you write one chunk of source code, and the compiler generates a
single chunk of object code which works with any combination of actual
parameters, provided that they are derived from the declared type.

#1 offers more potential for optimisation at the risk of code bloat. #2
eliminates the code bloat but also eliminates some potential for
optimisation.

In cases where either approach will work, the choice depends upon how much
you gain (i.e. how much the optimisation potential actually matters) and
how much you lose (i.e. how much code bloat will result). In general,
lower-level code results in #1 providing more gain for less cost, while
higher-level code reduces the gain and/or increases the cost.

#1 requires that the type is known at compile time, while #2 allows
the type to be determined at run time.

#1 works with primitive types, while #2 only works with
classes, so you would have to take the Java approach of creating class
wrappers for primitive types if you wanted to use #2.

#1 selects a template instance based upon all of the parameters,
while #2 dispatches solely upon the type of the "this" parameter.
 
S

Stuart Redmann

I am a bit confused about so many design approaches to even the
simplest of problems. I am not able work with all of them together. It
seems I have to pick one of these.

Mainly there seems a distinct choice between the two.
1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc.  (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

When do you do what. Can I say that if its a computation/algorithmic
problem we are solving- style 1. If it is one of software design -
style2. Is that true?

[snip]

If have heard somewhere that the Qt re-implementation of containers
has been done because (A) they were not satisfied with the STL
containers, and (B) they need an implementation that does not use so
many template related technology. Argument (B) were due to the fact
that they wanted to use Qt on the Nokia cell phone without having to
develop a C++ compiler that is sophisticated enough to compile every
template feature that STL code uses. I can't remember where I read
this, probably some Qt forum.

I'd say that containers are template based because most often you know
what should be inside your container. This is probably not so much a
performance issue but the only way to ensure type integrity.

With regard to the design question when to use templates and when to
use OO, I would always choose OO as first alternative. Only use
templates if OO is not sufficient to solve the problem (because of
performance reasons, type safety, extensibility).

That my 2cents.

Regards,
Stuart
 
J

Juha Nieminen

Stuart Redmann said:
I'd say that containers are template based because most often you know
what should be inside your container. This is probably not so much a
performance issue but the only way to ensure type integrity.

While type integrity is a useful feature, the efficiency benefits of
templated containers shouldn't be underestimated. They can be quite
significant.

In a typical OO language (which is not C++) for example a generic
dynamic array is implemented as, basically, an array of pointers/references
to dynamically allocated objects. In most of these languages the allocation
of these objects is not heavy, but they incur an inevitable memory overhead.
In other words, this scheme consumes more memory than an std::vector
containing object values does. (The memory consumption overhead is
relatively the larger the smaller the objects themselves are. In the
worst case the memory consumption can be over twice that of std::vector,
eg. when the objects themselves have the size of an int.)

In C++ an additional speed overhead is also usually imposed because
dynamic memory allocation is, unfortunately, a heavy operation, and if
you are going to allocate each individual object separately (rather
than eg. allocating them in a bunch as std::vector does), it will be
quite inefficient. Constructing a std::vector of pointers and dynamically
allocating the individual objects can be at worse an order of magnitude
slower than allocating a std::vector containing objects by value.
(Destroying the vector will also usually be slower.) This not to talk
about the memory fragmentation that such individual allocations may
cause (as any kind of memory defragmentation is all but impossible in
a C++ program).
With regard to the design question when to use templates and when to
use OO, I would always choose OO as first alternative. Only use
templates if OO is not sufficient to solve the problem (because of
performance reasons, type safety, extensibility).

I'd say the exact opposite.
 
S

Stuart Redmann

While type integrity is a useful feature, the efficiency benefits of
templated containers shouldn't be underestimated. They can be quite
significant.

[snip]

Total agreement from me. I just value the type integrity higher than
the performance gain (first get it right, than get it fast).



Juha said:
I'd say the exact opposite.

Maybe I should elaborate: I consider writing template code, which
behaves properly in all respects, much harder than writing OO code.
And I think that this opinion is shared by the majority of C++
programmers because most projects I have encountered on CodeProject or
SourceForge do not define new templates at all or only to a small
degree, most of them just use the existing templates from the STL.

Further I think that it is easy to use templates in such a way that
one violates encapsulation: For example if I want to implement the
Decorator Pattern, I can do it either the classical OO way using a
intermediate object or add the decorator functionality to the class
directly through a templated mix-in class. However, I cannot specify
that the mix-in class should only be used in conjunction with the
interface that should be decorated (at least I don't know how this
could be done without resorting to some nasty template meta-
programming).

The OO approach is more verbose: The decorator object exposes the
interface directly and forwards the calls to the decorated object with
the same interface: that's pretty straightforward to read. Even though
template code can achieve the same (and get it done more efficiently),
but the template mix-in may inadvertently be used with a different
interface that just happens to expose a method with the same name.

I find myself wishing for some way to tell the comiler that some
template parameter should be of some class type. The only way to
document this is to put in some comment in the template's description.

Regards,
Stuart
 
J

Jorgen Grahn

While type integrity is a useful feature, the efficiency benefits of
templated containers shouldn't be underestimated. They can be quite
significant.

[snip]

Total agreement from me. I just value the type integrity higher than
the performance gain (first get it right, than get it fast).



Juha said:
I'd say the exact opposite.

Maybe I should elaborate: I consider writing template code, which
behaves properly in all respects, much harder than writing OO code.

How is it hard? I find it quite easy. You just write your function or
class for one type, then go back and replace it with a T.

I don't try to write fully reusable multi-purpose libraries, though.

....
I find myself wishing for some way to tell the comiler that some
template parameter should be of some class type. The only way to
document this is to put in some comment in the template's description.

Why would you place such a restriction? I know of no useful
characteristics shared by all class types, but no other types.

/Jorgen
 
J

Jeff Flinn

Stuart said:
Stuart Redmann wrote:
....

I find myself wishing for some way to tell the comiler that some
template parameter should be of some class type. The only way to
document this is to put in some comment in the template's description.

Regards,
Stuart

see boost type_traits, static_assert, and [dis/en]able_if libs and
utilities.

Jeff
 
S

Stuart Redmann

Jorgen said:
Why would you place such a restriction? I know of no useful
characteristics shared by all class types, but no other types.

I phrased that quite badly. Maybe I should try with the following
example.

class Base
{
};

template<class T>
class Mixin : public T
{

};

What I want is a way to tell the compiler is that the type T of Mixin
should be of type Base or derived from Base. There is probably some
mechanism from boost, but that means that I have to read yet another
book to make it work (and heaven forbids that one makes some mistake
and has to wade a three-page long error message full of the innards of
boost ;-)

In my eyes the people behind boost are doing a terrific job of
providing the functionality that should have been part of C++ right
from the start. However, I remember that I read somewhere that the C++
template mechanism was never intended (by Bjarne?) to do what nowadays
is done by boost.

Also there seem to be some slightly different interpretations of the C+
+ standard with regard to some corner cases of the language that
should never be shown to the average C++ programmer but are essential
to some template tricks in boost. That's why I rather do not use
boost.

Regards,
Stuart
 
V

vincent.L

I phrased that quite badly. Maybe I should try with the following
example.

class Base
{

};

template<class T>
class Mixin : public T
{

};

What I want is a way to tell the compiler is that the type T of Mixin
should be of type Base or derived from Base. There is probably some
mechanism from boost, but that means that I have to read yet another
book to make it work (and heaven forbids that one makes some mistake
and has to wade a three-page long error message full of the innards of
boost ;-)

In my eyes the people behind boost are doing a terrific job of
providing the functionality that should have been part of C++ right
from the start. However, I remember that I read somewhere that the C++
template mechanism was never intended (by Bjarne?) to do what nowadays
is done by boost.

Also there seem to be some slightly different interpretations of the C+
+ standard with regard to some corner cases of the language that
should never be shown to the average C++ programmer but are essential
to some template tricks in boost. That's why I rather do not use
boost.

Regards,
Stuart


Most of Boost.TypeTraits has actually been included in the new c++
standard (C++11).
It is now part of the STL in the form of the type_traits header.

So your problem is actually easy to solve using standard C++ :


#include <type_traits>

class Base
{

};

template<class T>
class Mixin : public T
{
static_assert(std::is_base_of<Base, T>::value, "invalid type :
should derive from Base");
};
 
K

Keith H Duggar

Hello,
     I am a bit confused about so many design approaches to even the
simplest of problems. I am not able work with all of them together. It
seems I have to pick one of these.

Mainly there seems a distinct choice between the two.
1. The new generic programming way. All this stl algorithms, range
functions, transforms, generates and function objects etc.  (This is
my favourite for fun).

2. The object oriented, polymorphic, way. Say the trolltech QT
framework. You really wouldn;t be approaching with style1 if you were
to design something like QT. I guess.

When do you do what. Can I say that if its a computation/algorithmic
problem we are solving- style 1. If it is one of software design -
style2. Is that true?

[snip]

Always strive for simplicity above all else. In other words, the
"MIT approach" (or if you are in a pinch fall back to WIB):

http://en.wikipedia.org/wiki/Worse_is_better

For example, for code prefer in this order

1) free function
2) free template function
3) member function

for data prefer in this order

1) constant
2) local variable
3) member variable

(the above post itself is highly simplified, just trying to give
you a very rough high-view idea/example).

KHD
 
J

Jorgen Grahn

I phrased that quite badly. Maybe I should try with the following
example.

class Base
{
};

template<class T>
class Mixin : public T
{

};

What I want is a way to tell the compiler is that the type T of Mixin
should be of type Base or derived from Base. There is probably some
mechanism from boost, but that means that I have to read yet another
book to make it work (and heaven forbids that one makes some mistake
and has to wade a three-page long error message full of the innards of
boost ;-)

I suspected that was what you meant to say. But don't you normally get
that feature automatically, since you're likely to get type errors if
you pick the wrong T when you instantiate the template?

Or, you could force the issue manually:

const Base& dummy = something_of_type_t;
In my eyes the people behind boost are doing a terrific job of
providing the functionality that should have been part of C++ right
from the start. However, I remember that I read somewhere that the C++
template mechanism was never intended (by Bjarne?) to do what nowadays
is done by boost.

Sure, but that's not an argument against templates, is it?
Also there seem to be some slightly different interpretations of the C+
+ standard with regard to some corner cases of the language that
should never be shown to the average C++ programmer but are essential
to some template tricks in boost. That's why I rather do not use
boost.

If they are internal to the implementation, I don't mind. They can
implement Boost in microcode if they want.

I'm reluctant to use Boost myself, but that's more because much of it is
too complex to learn. Like Stroustrup writes:

"Sometimes, generality and simplicity coincide; in Boost, the
balance is IMO too often so far towards generality that novices
and average users are lost."

An average user who's lost. That's me when I read many of the
Boost documents.

/Jorgen
 
W

Werner

If have heard somewhere that the Qt re-implementation of containers
has been done because (A) they were not satisfied with the STL
containers,

This is not what I've heard. I've rather heard that at the time (of
original development) the STL was not portable enough (or that this
was their perception).
and (B) they need an implementation that does not use so
many template related technology. Argument (B) were due to the fact
that they wanted to use Qt on the Nokia cell phone without having to
develop a C++ compiler that is sophisticated enough to compile every
template feature that STL code uses. I can't remember where I read
this, probably some Qt forum.

Strange, as they use templates extensively in their own containers
too, apart from the fact that the containers in QT4 is to a large
degree STL algorithm compatible.

This is for instance the QT interface:

template <typename T>
class QList
{
//...
};

The only significant difference is the underlying memory management
(Qt not using allocators?).

Kind regards,

Werner
 
J

Jorgen Grahn

.
I favored generic programming for a while but after using it
in practice I have come out against it. For the following reasons:

1. It doesn't scale. All the template stuff quickly make your
compilation times unbearable. You might deal with that by hiding
generic code inside cpp files and never expose them in your interface.
Like e.g. VTK. But then you have taken away the ability to use generic
programming as a way of defining your interfaces.

2. Error messages suck. I don't really think the elegance of the
generic based solutions make up for time wasted in interpreting
template error messages.

3. Really hard to debug. When you create say a for_each, with some
bind2nd argument and a bunch other stuff, it is much harder to see what
is going on in the debugger than with a regular index based loop.

I haven't seen your code, but it must be very different from mine:
I have none of those problems.

There are better and worse ways to use templates, just for any other
tool.
4. The average C++ developer doesn't get it. This potentially increase
maintenance cost, because your average developer is not going to be
able to read that code.

The average C++ programmer doesn't get C++, in my experience.

/Jorgen
 
P

persres

So, I understand most people favor generic programming. Just as I
would have thought. c++0x, lambda etc have brought on a lot of
expressiveness and am hoping, if boost graph library and a lot of
others were rewritten today perhaps it might be much easier to use.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top