To bean or not to bean

S

Steven T. Hatton

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
notification.

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?
 
B

Bob Hairgrove

On Sat, 28 Aug 2004 04:39:31 -0400, "Steven T. Hatton"

[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.

<OT-advocacy-mode>
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.
</OT-advocacy-mode>

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.
 
V

Victor Bazarov

Bob Hairgrove said:
[..]
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
 
S

Steven T. Hatton

Bob said:
On Sat, 28 Aug 2004 04:39:31 -0400, "Steven T. Hatton"

[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.

<OT-advocacy-mode>
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.
</OT-advocacy-mode>

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
loading and execution of the program by the JVM.

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.
^^^^^^^^
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.
 
S

Steven T. Hatton

Victor said:
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.
 
P

Phlip

Steven said:
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
loading and execution of the program by the JVM.

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.
 
E

E. Robert Tisdale

Steven said:
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.
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.
 
S

Steven T. Hatton

Phlip said:
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".)
 
P

Phlip

Steven said:
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
will return to these techniques while exploring more Fault Navigation issues
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.
 
S

Steven T. Hatton

E. Robert Tisdale said:
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.


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.
 
S

Steven T. Hatton

Phlip said:
Use the Cpp for:

- token pasting
Why? What can that give me that I cannot achieve using the internal
features of the language?
- stringerization

I'm not familiar with the term. Care to explain?
- conditional compilation (oh, yeah. Everyone likes that one...)

I am aware that the Cpp is used for this. There have, as yet, been no
viable alternatives introduced, and accepted into the C++ standard.
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 will return to these techniques while exploring more Fault Navigation
issues 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.

I guess I'm not getting what that does for me. Can you explain how I would
gain from the use of such a macro? I don't use microsoft products very
often, so I really have no idea of what you are talking about. Can you
explain how I could use this macro without using a specific IDE?
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.

Who has dismissed C++?
 
E

E. Robert Tisdale

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

I'm questioning your interpretation of "Stroustrup's view on classes".
I'm assuming that you read something that Stroustup wrote and published
and that you aren't communicating with him privately
and that you are not reading his mind.
It would help if you could cite publication and, perhaps,
quote the passage that he wrote.
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.


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 functions
is contrary to philosophy that
a class should have a clearly defined invariant that is preserved
when operated on by invoking its member or friend functions 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.

It is an *indication* that you might be doing something wrong.
If only get and set methods are defined,
the object is nothing more than a "junk box".
An array (of any type) is an example of such an object.
A vector, matrix or tensor object is superficially similar to an array
but with vector arithmetic operations and other interesting methods.

I'll offer a more simple example:

class SocialSecurityNumber {
private:
unsigned long int Number;
public:
explicit
SocialSecurityNumber(unsigned long int n): Number(n) {
// throw exception if n does not represent a valid SSN
}
explicit
SocialSecurityNumber(std::string n) {
// throw an exception if n does not represent a valid SSN
}
operator unsigned long int(void) const {
return Number;
}
operator std::string(void) const {
std::eek:stringstream oss;
oss << Number/1000000 << '-'
<< (Number/10000)%100 << '-'
<< Number%10000;
return oss.str();
}
};

You can't do much with a social security number except set and get it.
In this case, the setter is a constructor and the getter is a type cast.
There is no "invarient" because a social security number can't change
except via the assignment operator

SocialSecurityNumber& operator=(const SocialSecurityNumber&);

All this shows is that even if all you have is getters and setters,
the needn't be named

SocialSecurityNumber::get(/* arguments */) const;
SocialSecurityNumber::set(/* arguments */);
 
S

Steven T. Hatton

E. Robert Tisdale said:
Steven T. Hatton wrote:
I'm questioning your interpretation of "Stroustrup's view on classes".
I'm assuming that you read something that Stroustup wrote and published
and that you aren't communicating with him privately
and that you are not reading his mind.
It would help if you could cite publication and, perhaps,
quote the passage that he wrote.

TC++PL(SE) 24.3.7.1 Invariants

"The values of the members and the objects referred to by members are
collectively called the /state/ of the object (or simply, its /value/). A
major concern of a class design is to get an object into a well-defined
state (initialization/construction), to maintain a well-defined state as
operations are performed, and finally to destroy the object gracefully.
The property that makes the state of an object well-defined is called
its /invariant/."
....
"Much of the skill in class design involves making a class simple enough to
make it possible to implement it so that it has a useful invariant that can
be expressed simply. It is easy enough to state that every class needs an
invariant. The hard part is to come up with a useful invariant that is
easy to comprehend and that doesn't impose unacceptable constraints on the
implementer or on the efficiency of the operations."
I'll offer a more simple example:

class SocialSecurityNumber {
private:
unsigned long int Number;
public:
explicit
SocialSecurityNumber(unsigned long int n): Number(n) {
// throw exception if n does not represent a valid SSN
}
explicit
SocialSecurityNumber(std::string n) {
// throw an exception if n does not represent a valid SSN
}
operator unsigned long int(void) const {
return Number;
}
operator std::string(void) const {
std::eek:stringstream oss;
oss << Number/1000000 << '-'
<< (Number/10000)%100 << '-'
<< Number%10000;
return oss.str();
}
};

You can't do much with a social security number except set and get it.
In this case, the setter is a constructor and the getter is a type cast.
There is no "invarient" because a social security number can't change
except via the assignment operator

SocialSecurityNumber& operator=(const SocialSecurityNumber&);

All this shows is that even if all you have is getters and setters,
the needn't be named

SocialSecurityNumber::get(/* arguments */) const;
SocialSecurityNumber::set(/* arguments */);

There is an invariant in the SocialSecurityNumber. It is established by
checking that it is valid when constructed, and maintained by checking that
it is valid when assigned to.
 
B

Bob Hairgrove

On Sat, 28 Aug 2004 21:18:57 -0400, "Steven T. Hatton"

[snip]
As for trailing underscores, what is your alternative?

I like to prefix the names of member data with "m_". It's only one
more character to type, and so much easier to read.
Agreed. What about situations such as:

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

I like the 80 column rule. It helps to use indentation to add
structure, as in the example above:

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

I like to move the lines after the first one far enough over to the
right to make it obvious that they are on the RHS. And I try to avoid
overly long names, too.

My compiler usually catches missing semicolons, but often has problems
reporting a missing comma ... i.e., there will be an error message,
but it will be somewhat cryptic.
 
S

Steven T. Hatton

Bob said:
On Sat, 28 Aug 2004 21:18:57 -0400, "Steven T. Hatton"

[snip]
As for trailing underscores, what is your alternative?

I like to prefix the names of member data with "m_". It's only one
more character to type, and so much easier to read.

I refuse! I will not be assimilated! I will never do that! ;) Actually,
after bashing my knuckles a few times on the alternative, that approach
does have its appeal. I just find it redundant. That's what /this/ is
for. And I do use /this/ religiously. The one place where it doesn't
serve me well is in the member initialization list.

I seem to recall reading that /this/ should be available there, but it has
never worked there for me when I tried to use it. I should try to look it
up in the Standard to see what is actually specified, but not right now.
bigLongLeftHandSide =
bigLongIdentifier
->bigLongMemberName
->yourGonnaWrapSucker
->bigLongFunctionName();

I like to move the lines after the first one far enough over to the
right to make it obvious that they are on the RHS. And I try to avoid
overly long names, too.

I am slowly adjusting to using shorter names in C++. The Java dogma is to
spell out everything, and follow strict rules of capitalization. The
advantage is that it is very predictable - so long as no one decides color
should have a 'u' in it. The disadvantage is that it tends to obscure the
logic a bit, and leads to the problem we are discussing.

The place where I encounter the need to wrap my member access strings is
when working with XML DOM.

As for indenting the second and subsequent '->' or '.', my editors don't do
that by default, and I find the meaning pretty clear without the additional
indentation.
My compiler usually catches missing semicolons, but often has problems
reporting a missing comma ... i.e., there will be an error message,
but it will be somewhat cryptic.

I prefer the editor to catch such mistakes. It took me some time to get
used to Emacs, but once I caught on, I found the syntax sensitive
indentation invaluable. Regardless of whether I'm writing DocBook EBNF XML
or C++, if I mess up the syntax, the indentation stops working after the
point where I made the mistake. KDevelop also supports a very similar kind
of behavior.

With JBuilder, the editor actually highlights syntax errors, and even
catches what I consider to be semantic errors such as using an identifier
which is not in scope. KDevelop does some of this, but I don't believe it
is even possible with C++ to provide the level of edit-time error detection
I've seen done with Java. See my signature for the reason.
 
P

Phlip

Why? What can that give me that I cannot achieve using the internal
features of the language?

The TEST_() macro uses it.
I'm not familiar with the term. Care to explain?

My #define db() sample.
I am aware that the Cpp is used for this. There have, as yet, been no
viable alternatives introduced, and accepted into the C++ standard.

That's my point. Those who bust on the CPP overlook CC, and CC works fine to
make large systems managable, such as Linux.

Another great thing about the CPP is it's language-agnostic (so long as you
don't find a language that does not balance "" and () operators, or use
commas for something silly). So the same macros can influence, for example,
your .cpp, .rc, and .idl files, etc.
I guess I'm not getting what that does for me. Can you explain how I would
gain from the use of such a macro? I don't use microsoft products very
often, so I really have no idea of what you are talking about. Can you
explain how I could use this macro without using a specific IDE?

It is a trace macro, like TRACE(). You put an expression in, and the macro
inserts its value into both the console and the Output panel (which all MS
Windows IDEs support).

Read my verbiage again.
language.

Who has dismissed C++?

I copied that repost from an essay, where, as a rhetorical technique, I
hypothesized that someone dismissed C++.
 
S

Steven T. Hatton

Phlip said:
The TEST_() macro uses it.

What is the TEST_() macro? I searched the ISO/IEC 14882:2003 for the string
"TEST" using acrobat, and got no hits. I assume it is not part of standard
C++?
My #define db() sample.

That doesn't explain what the word means.
That's my point. Those who bust on the CPP overlook CC, and CC works fine
to make large systems managable, such as Linux.

Linux is written in C. It is a very controlled development process that
requires a great deal of specialized expertise to work on. Working on any
given component does not require knowledge of a wide variety of rapidly
changing interfaces.

I really don't know what you mean by the "CC". To me, CC is a somewhat
antiquated alias for the C Compiler.

Now if you want to talk about program suites such as the KDE, /that/ is
written in C++ using Qt. I've been working with the KDE since spring of
1997. It is an extremely impressive project, with many gifted
contributors. The component of the KDE which I have spent a good deal of
the past several months working with is KDevelop. That is the IDE
distrubuted with the KDE. I am acutely aware of its capabilities and
limitations.

I've also worked with J2EE fairly extensively. For purposes of developing
enterprise applications such as the web based interface for the US Army's
personnel database, BEA's WebLogic is easier to use, and facilitates faster
development than anything I know of based on C++.
Another great thing about the CPP is it's language-agnostic (so long as
you don't find a language that does not balance "" and () operators, or
use commas for something silly). So the same macros can influence, for
example, your .cpp, .rc, and .idl files, etc.

That doesn't address the problems created by using the CPP.

http://www.freshsources.com/bjarne/ALLISON.HTM

//--------------excerpt-----------------------------
CUJ: What do you do for your day job now?

BS: I'm trying to build up a research group to focus on large-scale
programming -- that is, to do research on the use of programming in large
programs rather than just language design, just the study of small
(student) programs, or the exclusive focus on design and/or process. I
think that programming technique, programming language, and the individual
programmer have a central role in the development of large systems. Too
often, either the scale of industrial projects or the role of programming
is ignored. This research will involve work on libraries and tools.
....

CUJ: What is the next step in the evolution of C++?

BS: Tools/environments and library design. I'd like to see incremental
compilers and linkers for C++. Something like two seconds is a suitable
time for re-compiling and re-linking a medium-sized C++ program after a
change that is localized to a few functions. I'd like to see browsers and
analysis tools that know not only syntax but also the type of every entity
of a program. I'd like to see optimizers that actually take notice of C++
constructs and do a decent job of optimizing them, rather than simply
throwing most of the useful information away and giving the rest to an
optimizer that basically understands only C. I'd like to see debuggers
integrated with the incremental compiler so that the result approximates a
C++ interpreter. (I'd also like to see a good portable C++ interpreter.)
None of this is science fiction; in fact, I have seen experimental versions
of most of what I suggest -- and more. We still suffer from
first-generation C++ environments and tools.
....

The preprocessor is one of the main factors that has led to the lack of more
sophisticated C program development environments: the fact that the source
text seen by the programmer isn't the text seen by the compiler is a
crippling handicap. I think the time has come to be serious about
macro-free C++ programming.
//--------------end-excerpt-----------------------------
It is a trace macro, like TRACE(). You put an expression in, and the macro
inserts its value into both the console and the Output panel (which all MS
Windows IDEs support).

Read my verbiage again.

Either I'm missing something, or that is far from impressive. The average
Java IDE can trace code and show me the value of any variable in detail. I
can also browse through the activation stack which is presented as a
clickable tree with all the classes and class members available for
inspection.
 
P

Phlip

Steven said:
Phlip wrote:

What is the TEST_() macro? I searched the ISO/IEC 14882:2003 for the string
"TEST" using acrobat, and got no hits. I assume it is not part of standard
C++?

Steve, people are allowed to write other macros than those that appear in
The Standard. Google this newsgroup for my street name, TEST_, and
Steinbach.
That doesn't explain what the word means.

Look inside my macro for the # operator.
Linux is written in C.

Snip from here down. I can't find evidence you are reading my posts.

Please take a deep breath, and entertain the idea that passionately decrying
a handful of keywords is a kind of zealotry.
 
S

Steven T. Hatton

Phlip said:
Steve, people are allowed to write other macros than those that appear in
The Standard. Google this newsgroup for my street name, TEST_, and
Steinbach.

This is silly. You used a macro that you wrote as an example that I am
expected to be familiar with, without even mentioning that you wrote it.
Look inside my macro for the # operator.

Perhaps you could simply provide a definition for the term. My attempting
to extract a definition from an example has the significant potential for
my arriving at a different definition than the one you intend.
Snip from here down. I can't find evidence you are reading my posts.

Please take a deep breath, and entertain the idea that passionately
decrying a handful of keywords is a kind of zealotry.

Sorry if you were confused by my use of words I learned in college when I
studied computer science. I can't say I will refrain from doing so in the
future, but I will do my best to restrict my vocabulary when addressing you
directly.

Now, back to the topic at hand. I changed the subject field in the heading
to reflect the fork this thread has taken. For the moment, forget any of
my own comments regarding the Cpp, and explain to the news group where
Bjarne Stroustrup is in error regarding the opinions expressed in the
following:


http://www.freshsources.com/bjarne/ALLISON.HTM

//--------------excerpt-----------------------------
 CUJ: What do you do for your day job now?

BS: I'm trying to build up a research group to focus on large-scale
programming -- that is, to do research on the use of programming in large
programs rather than just language design, just the study of small
(student) programs, or the exclusive focus on design and/or process. I
think that programming technique, programming language, and the individual
programmer have a central role in the development of large systems. Too
often, either the scale of industrial projects or the role of programming
is ignored. This research will involve work on libraries and tools.
....

 CUJ: What is the next step in the evolution of C++?

BS: Tools/environments and library design. I'd like to see incremental
compilers and linkers for C++. Something like two seconds is a suitable
time for re-compiling and re-linking a medium-sized C++ program after a
change that is localized to a few functions. I'd like to see browsers and
analysis tools that know not only syntax but also the type of every entity
of a program. I'd like to see optimizers that actually take notice of C++
constructs and do a decent job of optimizing them, rather than simply
throwing most of the useful information away and giving the rest to an
optimizer that basically understands only C. I'd like to see debuggers
integrated with the incremental compiler so that the result approximates a
C++ interpreter. (I'd also like to see a good portable C++ interpreter.)
None of this is science fiction; in fact, I have seen experimental versions
of most of what I suggest -- and more. We still suffer from
first-generation C++ environments and tools.
....

The preprocessor is one of the main factors that has led to the lack of more
sophisticated C program development environments: the fact that the source
text seen by the programmer isn't the text seen by the compiler is a
crippling handicap. I think the time has come to be serious about
macro-free C++ programming.
//--------------end-excerpt-----------------------------
 
E

E. Robert Tisdale

Steven said:
TC++PL(SE) 24.3.7.1 Invariants

"The values of the members and the objects referred to by members are
collectively called the /state/ of the object (or simply, its /value/). A
major concern of a class design is to get an object into a well-defined
state (initialization/construction), to maintain a well-defined state as
operations are performed, and finally to destroy the object gracefully.
The property that makes the state of an object well-defined is called
its /invariant/."
...
"Much of the skill in class design involves making a class simple enough to
make it possible to implement it so that it has a useful invariant that can
be expressed simply. It is easy enough to state that every class needs an
invariant. The hard part is to come up with a useful invariant that is
easy to comprehend and that doesn't impose unacceptable constraints on the
implementer or on the efficiency of the operations."


There is an invariant in the SocialSecurityNumber.
It is established by checking that it is valid when constructed
and maintained by checking that it is valid when assigned to.

Yes. The invariant is trivial.
And I think that your understanding of invariance is consistent
with the way that Stroustrup uses the term.
Notice that, in the example above, there is no way to construct
an invalid SocialSecurityNumber and no assignment is defined
except the default assignment from another valid SocialSecurityNumber.
 

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

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top