Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-03-31 10:44:18


From: Tushar <tushar_at_[hidden]>
> On Tue, 2005-03-29 at 01:29, Rob Stewart wrote:
> > From: Andreas Pokorny <andreas.pokorny_at_[hidden]>
> > > On Mon, Mar 28, 2005 at 07:36:15PM +0530, Tushar <tushar_at_[hidden]> wrote:
> > > > On Fri, 2005-03-25 at 01:06, Andreas Pokorny wrote:
> >
> > > > > > 2.C++ has much of the libs using STL. The only problem is STL is not a
> > > > > > object oriented.
> > > > > Where is the problem? Containers are object, algorithms are not. Looks
> > > > > perfectly good to me.
> >
> > Agreed. STL not being (entirely) OO is not a problem in any way.
> It is. It makes it difficult to document/design things with UML and
> related documentation tools like doxygen or javadoc

This is not a problem. It is your understanding of the tools.

> > > > Yes it is. But that is case of pure algorithms like sorting. But for
> > > > many case, one wants to combine data and algorithm.(If I am correct,
> > > > this is called encapsulation in OOPS). So for example, I can have a
> > > > linked list which can sort itself. According to STL, I will create a
> > > > linked list and pass it to method sort.
> > >
> > > Algorithms can be defined without refering to a specific type, usually
> > > it is enough to define the concept of the data.
> >
> > Right. The containers in the STL do have member functions, so
> > they are OO. They also participate in a more generic scheme that
> > allows apply algorithms to iterator ranges while selecting the

s/apply/applying/

> > most appropriate implementation. Therefore, some functionality
> > that is common to several containers is not implemented via class
> > member functions, but rather as free functions that can be
> > applied to the containers. (See
> > http://www.cuj.com/documents/s=8042/cuj0002meyers/ for more on
> > this idea.)
>
> I have gone through above doc. First I do not still understand how
> non-member functions increase encapsulation.e.g. He is trying to say
> that, I have a class X
>
> Class X
> {
> int x,y,z;
> X(int x,int y,int z)
> {
> Set(X);Set(y);Set(Z);
> }

Why would you do this? I realize that these are ints, but as a
rule, you need to use an initializer list:

        X(int x, int y, int z)
           : x(x)
           , y(y)
           , z(z)
        {
        }

> X(int x)
> {
> Set(X);SetY(0);SetZ(0);
> }

        X(int x, int y, int z)
           : x(x)
           , y(0)
           , z(0)
        {
        }

> SetX(int x);//implementation not shown. You people know it.
> SetY(int y)
> SetZ(int z)
>
> }

For now, I'll refrain from making comments on the other design
errors in this class and hope they exist only because you quickly
created an example for your discussion.

> According to author, if I change x to xx, I need to rewrite three
> functions.But its clearly not the case. This is simple example. But

No. His point is that you must look at all member functions in
the class to determine whether the name change affects them.
That you can say not all must be rewritten is because you looked
at them and (trivially) determined that they were not affected by
the name change.

A friend function or, better yet, a free function that isn't a
friend, is totally insulated from the name change provided the
data member is private. In that case, you can completely ignore
non-member functions when making that name change.

> there can be many more. Its all about reusing code, be it inside class,
> out side class or with pure C code. One can always have minimum code for
> a class method that effectively uses other methods.
>
> Second point about that is, it makes some syntax issues that author
> also agrees.Like
>
> Wombats w; //See above doc for Wombats.
> w.eat("ff");
> sleep(w);
>
> The biggest problem for some one new like me is of knowing capability of
> class. If i go through doc of class X, and there is method "eat", I know
> X can eat.(Like Wombats can eat.) But when I do not see "sleep" as
> member of that class, first impression is that X can not sleep.(I am
> used to think that way. Sorry).

Get used to thinking differently. Modern C++ favors non-member
functions where possible. Even eat() would frequently be
implemented thusly:

   void
   eat(Wombats const & w, std::string const & food)
   {
      w.eat(food);
   }

That leads to altering the example to be:

   Wombats w;
   eat(w, "ff");
   sleep(w);

You don't have to do that in all cases, but it is necessary to
make Wombats accessible via parametric rather than dynamic
polymorphism (from function templates rather than via abstract
interfaces).

The documentation issue simply boils down to the modern notion of
Concepts. To support the eat() and sleep() free functions, you
can define Eater and Sleeper Concepts such that objects
satisfying those concepts support this usage:

   Eater:
      eat(x, food);

   Sleeper:
      sleep(x);

Now, many types can be documented as satisfying those Concepts.
Once you know that, you'll know that the usage for those Concepts
is valid for the type at hand.

> > IOW, in Java, everything is a reference counted pointer, so
> > copies are cheap. In C++, particularly in Boost, you spell that
> > with boost::shared_pointer.
> OK. I will like to copy everything not a primitive data type. Do you
> think, using one more class for everything that I want to use pointer to
> is a good thing? Let me to go through doc of shared_pointer,then I will
> comment more on this issue.

void * suffices when you want a pointer to anything. Of course
you can't get back the dynamic type anymore, so it's of limited
value.

The point is that there are many things possible, but experience
has shown that few are best practice. We long ago recognized
that a common, root class is a bad idea for most cases.

> I agree. I have made some wrong statements. Original point was use of
> templates. Can any one tell me how it help to write code other then for
> primitive data types and classes that implements operator like =,<= to
> simulate primitive data type.

I don't understand your question.

> > > Either add everything you might possibly ever need in every application
> > > in the library base class, or dynamically cast to the type you like, and
> > > handle cast exceptions in every function of your code.
> >
> > The point you make is valid: there is a reason we don't write C++
> > with a common root class. We learned long ago to avoid the
> > problems that creates. (One example of the problem is that you
> > force MI on classes that currently derive from some type.
> > Another is how to integrate code from two different frameworks,
> > each with its own common base class.)
> OK I agree. May be having a common base class will lead to some problem
> in case of MI.

There are many other problems besides forcing MI.

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

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