Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   To bean or not to bean (http://www.velocityreviews.com/forums/t285265-to-bean-or-not-to-bean.html)

 Steven T. Hatton 08-28-2004 08:39 AM

To bean or not to bean

Stroustrup's view on classes, for the most part, seems to be centered around
the notion of invariants. After a bit of adjusting to the use of yamt (yet
another math term) in computer science, I came to appreciate some of the
significance in what he is asserting. I believe a good example would be
the Riemann-Christoffel curvature tensor. In the 4-space of general
relativity, there are 256 components of this beast.

One approach to representing this tensor might be a struct with 256 float
members all public. The user simply treats it as a big bag of bits. This
tensor - by definition - has certain invariant properties which must remain
constant under certain groups of operations. That means that, either the
user must be carful to enforce the rules preserving the invariants if he is
going to modify the components directly. For this reason, it makes sense
to put the data in a class and only allow controlled access through the use
of invariant preserving access methods.

Stroustrup also argues that a reasonable test to determine if you really do
have a class with invariants is to ask if there are multiple
representations of the data structure which are functionally equivalent.
Indeed there are for this tensor. And that can actually buy you a lot.
Although the tensor has 256 components, only 20 are independent. That
means you can represent the tensor as an object of only 20 data members,
and if circumstances demand all 256 components be available in the program,
that can be accomplished by multiply indexing the storage locations through
access methods which collectively give the illusion that the entire tensor
exists with all of it's 256 components.

So far, so good. I pretty much agree with his reasoning for distinguishing
between what should properly be represented as a class with private (or
protected) data, as opposed to simply a struct with all public members and
direct user access. I like a lot of the careful discernment found in C++ as
opposed to Java, for example. There are not concepts of constness and
mutable caching in typical Java literature. That shows me C++ has
expressive powers that go well beyond other general purpose languages.

There is however, one point that Stroustrup doesn't address regarding
'accessor' methods. He tells us we should avoid writhing classes with
direct accessor methods to manipulate the data. The reasoning seems
obvious to me. If the user has a reason to micro-manage the data, it
probably doesn't have a clearly defined invariant that could and should be
preserved under the operations applied to it collectively.

The Java community operates with a different philosophy regarding data and
classes. Basically, nothing is public other than static constants, and
accessor methods. The simplest notion of a been in Java is just a class
with data members read and written through the mediation of 'set' and 'get'
methods. The payoff to this very protective approach to managing data is
that it facilitates such design features as event-listener patterns, and
concurrent programming. The access methods provide a natural means of
locking access to data, and also monitoring access for purposes of event

One of the more important developments in TC++PL(SE) is the creation of
abstract user interface components as a means of demonstrating the various
options for using inheritance and class hierarchies. Stroustrup argues -
correctly IMO - that a programmer should strive to solve problems
independently of the proprietary libraries he may be developing with.

This is what I have been calling an AUI (abstract user interface) for a few
years. I decided I would try the exercise as part of a project I'm working
on with the goal of visually representing the various access patterens use
to simulate multidimensional arrays using valarray, slices, and gslices.
The program creates a tree of grid cell objects which become the elements
of the graphical representation of the multidimensional matrix.

I created an interface class with all pure virtual functions, and one data
member. The data member is an object that holds default values to be
shared among the different grid elements. This may seem somewhat
convoluted, but it enables me to do some interesting things, such as change
the value of the default values object, notify all the grid cell objects
which own a DefaultBox that their defaults have been changed, and they need
to consider updating.

That demonstrates what I was getting at regarding the use of an
event/listener (observer) pattern to adapt to changes in a particular
object. There's something else that my design also seems to dictate.

The class used to default initialize grid cells is a good example of what
I'm finding appropriate for my design, and which seems to contradict
Stroustrup's recommendation to avoid 'set' and 'get' functions. That's
actually a pretty significant part of what my grid cell objects consist of.
That is, data members with read and mutate functions for the data.

#ifndef STHBOXDEFAULTS_H
#define STHBOXDEFAULTS_H
#include <string>

namespace sth
{
using std::string;
/**
@author Steven T. Hatton
*/
class BoxDefaults
{
public:
BoxDefaults( bool is_leaf_ = false,
bool is_vertical_ = false,
string text_ = "[...]",
RgbColor bg_color_ = RgbColor::YELLOW,
RgbColor text_color_ = RgbColor::BLACK,
RgbColor edge_color_ = RgbColor::RED,
double h_ = 35,
double w_ = 50,
double border_w_ = 5,
double x_ = 0,
double y_ = 0,
int bg_z_ = 1,
int text_z_ = 2
)
: is_leaf( is_leaf_ ),
is_vertical( is_vertical_ ),
text( text_ ),
bg_color( bg_color_ ),
text_color( text_color_ ),
edge_color( edge_color_ ),
h( h_ ),
w( w_ ),
border_w( border_w )
{}

virtual ~BoxDefaults(){}
/**
* Are child boxes layed out vertically?
*/
virtual bool Is_vertical() const
{
return this->is_vertical;
}

virtual void Is_vertical(const bool& is_vertical_)
{
this->is_vertical = is_vertical_;
}

/**
* Is this a leaf node?
*/
virtual bool Is_leaf() const
{
return this->is_leaf;
}

virtual void Is_leaf(const bool& is_leaf_)
{
this->is_leaf = is_leaf_;
}

virtual RgbColor Bg_color() const
{
return this->bg_color;
}

virtual void Bg_color(const RgbColor& bg_color_)
{
this->bg_color = bg_color_;
}
/* etc., etc. */

};
}

This seems rather natural to me, but it makes me a bit uneasy, because
Stroustrup has suggested it may not be a good design approach. I will not
that he also insists that his advice and opinions are not intended as
inviolable dictates, nor are they expected to be applicable equally in all
circumstances.

What is your opinion of the use of the 'Java Beans' design approach? I
realize there is more to a Bean than simply a class with data, events, and
associated listeners. Nonetheless, that seems to be the definitive essence
of what they areally are. There are some aspects of the JavaBean
specification that strike me as arcane and seem to offer far more potential
trouble than potential worth. I do believe the general approach is
something worth understanding, and considering for C++ design. Here's the
JavaBean spec:

http://java.sun.com/products/javabeans/docs/spec.html

What do you think of these ideas as potentially applicable to C++ code?
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 Bob Hairgrove 08-28-2004 10:34 AM

Re: To bean or not to bean

On Sat, 28 Aug 2004 04:39:31 -0400, "Steven T. Hatton"
<susudata@setidava.kushan.aa> wrote:

[snip]
>So far, so good. I pretty much agree with his reasoning for distinguishing
>between what should properly be represented as a class with private (or
>protected) data, as opposed to simply a struct with all public members and
>direct user access. I like a lot of the careful discernment found in C++ as
>opposed to Java, for example. There are not concepts of constness and
>mutable caching in typical Java literature. That shows me C++ has
>expressive powers that go well beyond other general purpose languages.

Every language should have its strong points which distinguish it from
other languages, giving it its reason for existence. I'll only say
that I like C++ because it allows the developer to be as much or as
little OOP as she likes. With Java, you are pretty much stuck with OOP
whether or not that is the appropriate tool for the task at hand.

I'll snip the rest because I merely want to comment on your naming
style:

[snip]
> class BoxDefaults
> {
> public:
> BoxDefaults( bool is_leaf_ = false,
> bool is_vertical_ = false,
> string text_ = "[...]",
> RgbColor bg_color_ = RgbColor::YELLOW,
> RgbColor text_color_ = RgbColor::BLACK,
> RgbColor edge_color_ = RgbColor::RED,
> double h_ = 35,
> double w_ = 50,
> double border_w_ = 5,
> double x_ = 0,
> double y_ = 0,
> int bg_z_ = 1,
> int text_z_ = 2
> )
> : is_leaf( is_leaf_ ),
> is_vertical( is_vertical_ ),
> text( text_ ),
> bg_color( bg_color_ ),
> text_color( text_color_ ),
> edge_color( edge_color_ ),
> h( h_ ),
> w( w_ ),
> border_w( border_w )

^^^^^^^^
Oops ... recursive initialization here!
This is why I do not like trailing underscores.

Also, what do you think of this:
: is_leaf ( is_leaf_ )
, is_vertical( is_vertical_ )
, text ( text_ )
, bg_color ( bg_color_ )
, text_color ( text_color_ )
, edge_color ( edge_color_ )
, h ( h_ )
, w ( w_ )
etc. as opposed to having the commas at the end? I find it much easier
to avoid superfluous comma errors like this because I don't have to
read to the end of the line to find it.

--
Bob Hairgrove

 Victor Bazarov 08-28-2004 02:14 PM

Re: To bean or not to bean

"Bob Hairgrove" <invalid@bigfoot.com> wrote...
> [..]
> Also, what do you think of this:
> : is_leaf ( is_leaf_ )
> , is_vertical( is_vertical_ )
> , text ( text_ )
> , bg_color ( bg_color_ )
> , text_color ( text_color_ )
> , edge_color ( edge_color_ )
> , h ( h_ )
> , w ( w_ )
> etc. as opposed to having the commas at the end? I find it much easier
> to avoid superfluous comma errors like this because I don't have to
> read to the end of the line to find it.

That's my choice as well (without the excessive spaces, though).
Makes adding things clearer, especially to the end, when otherwise
I usually forget to add the comma after the last initialiser.

V

 Steven T. Hatton 08-29-2004 01:18 AM

Re: To bean or not to bean

Bob Hairgrove wrote:

> On Sat, 28 Aug 2004 04:39:31 -0400, "Steven T. Hatton"
> <susudata@setidava.kushan.aa> wrote:
>
> [snip]
>>So far, so good. I pretty much agree with his reasoning for
>>distinguishing between what should properly be represented as a class with
>>private (or protected) data, as opposed to simply a struct with all public
>>members and direct user access. I like a lot of the careful discernment
>>found in C++ as
>>opposed to Java, for example. There are not concepts of constness and
>>mutable caching in typical Java literature. That shows me C++ has
>>expressive powers that go well beyond other general purpose languages.

>
> Every language should have its strong points which distinguish it from
> other languages, giving it its reason for existence. I'll only say
> that I like C++ because it allows the developer to be as much or as
> little OOP as she likes. With Java, you are pretty much stuck with OOP
> whether or not that is the appropriate tool for the task at hand.

Somewhere out on the net there is a lexer "written in Java" that consists of
one class with all of the code written as member functions. The program is
virtually indistinguishable from C other than the use of the necessary
class to get the thing bootstrapped. I believe a lot of people are missing
the real significance of the design choice made by the Java designers that
requires all code to be in a class. It wasn't really done for the benefit
of the application programmer. It was done because it facilitates the

To some extent, it is an artifact of the way the language is implemented.
If you think of the top level class as part of the execution environment,
you will understand there is far less difference between Java and C++ in
this regard than there otherwise may seem.

As you've suggested this is somewhat off topic. I'm discussing it here
because it provides a contrast to C++ that might serve to solidify
understanding, and lead to new approaches to programming in C++. I don't
believe Trolltech strove to emulate Java in developing their toolkit, but
there are some significant similarities in the way things are done in Qt.

Unlike Java, Qt does not restrict you from using namespace local
declarations, but it does encourage the design approach of putting
everything in some class, and treating your program as a collection of
interacting objects.

Note: what follows is pseudo-history:

Think of it like this. Originally programs were a long sequence of
instructions read in and executed one after the other. Some of these
instructions were able to tell the computer to goto and execute a
previously encountered instruction and to continue from there sequentially
as if the instruction had appeared after the branch point.

Then some guy decided goto was a four-letter-word, and advocated banishing
its use. The result was to hide goto instructions behind fancy constructs
such as function calls, and switch statements. Nonetheless, a program
remained a sequence of instructions to be executed as if the computer were
reading down a page, with the understanding that it may examine a
cross-reference at times. That is what C-style programming is.

At some point in the ancient past the notion of an eventloop was discovered.
The result was Emacs. Emacs later mated with C, resulting in several
offspring. Namely XEmacs, ECMAScript (JavaScript), (GNU)Emacs, Mozilla
etc. The person who facilitated this seemingly unnatural union of Lisp and
C was a man named James Gosling. This is the same James Gosling who
invented Java. Note that an interesting thing happened when these ideas
were merged. Some of the offspring are programs, and some are programming
languages. And some can't make up their mind which way they go.

At the same time as these offspring were being engendered and/or maturing a
more carfully arranged union between C and Simula was consummated. The
result was the highly cultured and demanding C++. C++ retains the original
sequential execution model inherited from C. C++ is a
*_programming_language_* not a program (damnit!) And that's the fundamental
difference between C++ and Java.

>> border_w( border_w )

> ^^^^^^^^
> Oops ... recursive initialization here!
> This is why I do not like trailing underscores.

I dislike the entire member initialization facility in C++. As for trailing
underscores, I don't get stung like that very often. As long as I retain
consistency, it is easy to identify such errors. Note the code you are
critiquing was copied directly out of the edit buffer of a program under
development. I hadn't even completed the member initialization block. Any
system such as the use of trailing underscores is subject to error. The
only thing worse is to not have a system at all. The use of leading
underscores is actually reserved for the implementation, though a program
can define and use such identifiers without errors being generated,
provided there are not conflicts with the implementations use of the same.

> Also, what do you think of this:
> : is_leaf ( is_leaf_ )
> , is_vertical( is_vertical_ )
> , text ( text_ )
> , bg_color ( bg_color_ )
> , text_color ( text_color_ )
> , edge_color ( edge_color_ )
> , h ( h_ )
> , w ( w_ )
> etc. as opposed to having the commas at the end?

I used to be a strong advocate of putting commas at the beginning of such
continued lines, but that was contrary to the culture in which I found
myself. I do like the style, and, after testing the auto-formatting in
KDevelop, and Emacs, I have discovered that both allign the code quite
nicely in the way you have shown above.

I also agree regarding the placement of the leading parentheses. I was
experimenting with the alternative because the long whitespace between the
identifier and the opening parenthesis also bothers me a bit. Your
approach is easier on the eye.

As for trailing underscores, what is your alternative?

> I find it much easier
> to avoid superfluous comma errors like this because I don't have to
> read to the end of the line to find it.

Agreed. What about situations such as:

bigLongLeftHandSide
= bigLongIdentifier
->bigLongMemberName
->yourGonnaWrapSucker
->bigLongFunctionName();
?

-- "[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 Steven T. Hatton 08-29-2004 01:28 AM

Re: To bean or not to bean

Victor Bazarov wrote:

> That's my choice as well (without the excessive spaces, though).
> Makes adding things clearer, especially to the end, when otherwise
> I usually forget to add the comma after the last initialiser.
>
> V

For me, that trailing comma gone missing becomes quite obvious when I C-x
C-h C-M-\ the remaining line are shot off the right side of the page into
oblivion. Same with KDevelop.
-- "[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 Phlip 08-29-2004 02:03 AM

Re: To bean or not to bean

Steven T. Hatton wrote:

> Somewhere out on the net there is a lexer "written in Java" that consists

of
> one class with all of the code written as member functions. The program

is
> virtually indistinguishable from C other than the use of the necessary
> class to get the thing bootstrapped. I believe a lot of people are

missing
> the real significance of the design choice made by the Java designers that
> requires all code to be in a class. It wasn't really done for the benefit
> of the application programmer. It was done because it facilitates the

You cannot legislate morality.

In Ruby, everything is a method. Ruby does not enforce this by beating the
programmer with syntax errors for their "heresy". Ruby enforces this by
helping. It provides a global object, and all statements execute within its
context. Because one cannot step outside this cosmological object,
everything in Ruby is inside an object, without syntax errors if you decline
to create an object.

(However, in Ruby, nothing will stop you from writing everything into one
long method... You cannot legislate morality. You can, however, legislate
immorality.)

> As you've suggested this is somewhat off topic. I'm discussing it here
> because it provides a contrast to C++ that might serve to solidify
> understanding, and lead to new approaches to programming in C++. I don't
> believe Trolltech strove to emulate Java in developing their toolkit, but
> there are some significant similarities in the way things are done in Qt.

F--- topicality. And Qt came first, right?

> -- "[M]y dislike for the preprocessor is well known. Cpp is essential in C
> programming, and still important in conventional C++ implementations, but
> it is a hack, and so are most of the techniques that rely on it. ...I

think
> the time has come to be serious about macro-free C++ programming." - B. S.

The preprocessor rules.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces

 E. Robert Tisdale 08-29-2004 02:42 AM

Re: To bean or not to bean

Steven T. Hatton wrote:

> Stroustrup's view on classes, for the most part, seems to be centered around
> the notion of invariants. After a bit of adjusting to the use of yamt
> (yet another math term) in computer science,
> I came to appreciate some of the significance in what he is asserting.

You probably misunderstood what Stroustrup was saying.
There is nothing terribly profound in language design.
It is a mistake to read too much into what Stroustup says.
He really tries to explain his ideas in the most straight-forward manner
using *plain* English.

> I believe a good example would be the Riemann-Christoffel curvature tensor.

No, it isn't a good example.
Very few computer programmers have cause to truck with such things.

A C++ class (or struct) is used
to introduce a User Defined Type (UDT) into a program.
A C++ class is most useful in implementing an Abstract Data Type (ADT).
The reason for data hiding (private data members) is practical.
It allows the class library developer to change the data representation
without any changes to application programs which use the class library
except, possibly, recompiling the application program and linking in
the revised class library.

 Steven T. Hatton 08-29-2004 02:52 AM

Re: To bean or not to bean

Phlip wrote:

> F--- topicality. And Qt came first, right?

Qt development begain in 1991, and the first public release was on the 20th
of May, 1995. The same week as the first release of Java.

> The preprocessor rules.

The preprocessor is the main reason that there is no serious C++ contender
to the highly successful J2EE development platform. The Cpp, and the
techniques it supports do not scale to that level of programming.
Stroustrup has some opinions that I don't fully accept. AAMOF, my
intention in beginning this thread was to discuss one such opinion. In the
past, when I have taken a position contrary to his, I eventually came to
realize he was more correct than I originally thought. I can't imagine
anyone has a more extensive understanding of the relationship between C++
and the Cpp than he does. Why do you think he is wrong about it? (I can
only assume that was your intended meaning in saying "The preprocessor
rules".)

--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

 Phlip 08-29-2004 03:08 AM

Re: To bean or not to bean

Steven T. Hatton wrote:

> The preprocessor is the main reason that there is no serious C++ contender
> to the highly successful J2EE development platform. The Cpp, and the
> techniques it supports do not scale to that level of programming.
> Stroustrup has some opinions that I don't fully accept. AAMOF, my
> intention in beginning this thread was to discuss one such opinion. In

the
> past, when I have taken a position contrary to his, I eventually came to
> realize he was more correct than I originally thought. I can't imagine
> anyone has a more extensive understanding of the relationship between C++
> and the Cpp than he does. Why do you think he is wrong about it? (I can
> only assume that was your intended meaning in saying "The preprocessor
> rules".)

Use the Cpp for:

- token pasting
- stringerization
- conditional compilation (oh, yeah. Everyone likes that one...)

Putting those inside a C language would make it not a C language. And they
permit techniques that more "modern" languages need but can't do.

A repost:

Visual Studio surfs to errors using <F8>: Go To Output Window Next Location.
The Windows SDK function to write text into the output panel, for this
feature to read it and surf to an error, is OutputDebugString().
Putting them all together yields this killer trace macro:

#define db(x_) do { std::stringstream z; \
z << __FILE__ << "(" << __LINE__ << ") : " \
#x_ " = " << x_ << endl; \
cout << z.str() << std::flush; \
OutputDebugStringA(z.str().c_str()); \
} while (false)

That takes any argument, including expressions, which support operator<<. We
in C++.

db(q) pushes "C:\path\source.cpp(99) : q = 5\n" into the Output Debug panel.
<F8> parses the file name and line number and navigates your editor directly
to the line containing the db(q).

Those are major wins. Tracing with db() is very low cost for very high
feedback.

C++ has flaws. But those of you inclined to dismiss it entirely are invited
to write db(), with all these features, in your favorite language.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces

 Steven T. Hatton 08-29-2004 04:03 AM

Re: To bean or not to bean

E. Robert Tisdale wrote:

> Steven T. Hatton wrote:
>
>> Stroustrup's view on classes, for the most part, seems to be centered
>> around
>> the notion of invariants. After a bit of adjusting to the use of yamt
>> (yet another math term) in computer science,
>> I came to appreciate some of the significance in what he is asserting.

>
> Please site passage an verse.

Regarding what? I'm not sure what you are questioning.

> You probably misunderstood what Stroustrup was saying.
> There is nothing terribly profound in language design.
> It is a mistake to read too much into what Stroustup says.
> He really tries to explain his ideas in the most straight-forward manner
> using *plain* English.
>
>> I believe a good example would be the Riemann-Christoffel curvature
>> tensor.

>
> No, it isn't a good example.
> Very few computer programmers have cause to truck with such things.

For my purposes, it was a good example. It is irrelevant whether a person
understand the full definition of the tensor. Only that it has invariants,
and that it has multiple data elements, some of which are redundant.

> A C++ class (or struct) is used
> to introduce a User Defined Type (UDT) into a program.
> A C++ class is most useful in implementing an Abstract Data Type (ADT).
> The reason for data hiding (private data members) is practical.
> It allows the class library developer to change the data representation
> without any changes to application programs which use the class library
> except, possibly, recompiling the application program and linking in
> the revised class library.

I'm not sure how that really address my question. I am asking whether the
creation of a class that consists of data members which are all
manipulatable through the use of access funcitons is contrary to philosophy
that a class should have a clearly defined invariant that is preserved when
operated on by invoking its member functions, or friend functions.

More specifically, I am asking if the creation of a class that consists of
nothing but data fields and set and get methods is an indication that I am
doing something wrong.
--
"[M]y dislike for the preprocessor is well known. Cpp is essential in C
programming, and still important in conventional C++ implementations, but
it is a hack, and so are most of the techniques that rely on it. ...I think
the time has come to be serious about macro-free C++ programming." - B. S.

All times are GMT. The time now is 03:40 PM.