Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

having the compiler enforce "good programming style"

2 views
Skip to first unread message

Michael Jørgensen

unread,
Mar 17, 2005, 4:49:50 PM3/17/05
to
Hi,

Here is an idea I've been thinking about for a while: The idea is to have
the compiler enforce "good programming style". Since there are differing
views on such matters, it should be configurable in the form of a text file,
and passed to the compiler as a command line parameter, i.e. something
like "-style=<file>".

The whole idea is to provide lint-like capability to the compiler, but also
to go a step or two beyond that:

When programming in C++, some constructs are legal but considered "bad
practice". So, a company might want to enforce a policy that forbids, e.g.
- C style casts
- malloc and friends.
- classes where only some of: destructor, copy constructor, and assigment
operator are defined.
- inconsistent indentation.
- inconsistent variable naming.
- missing comments.
- etc.

Legacy code would be compiled with a default style that makes few or no
restrictions.

Different companies will of course have different style files, but
presumably over time the community could agree to a select few "widely
adopted" styles.

Ideally, such a style file will completely replace the existing coding
standards, and in fact will make for consistent documentation of the local
policy.

Any comments, anyone?
Has there been any work done along these lines?

-Michael.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Pete Becker

unread,
Mar 18, 2005, 8:06:13 AM3/18/05
to
Michael Jørgensen wrote:
>
> Here is an idea I've been thinking about for a while: The idea is to have
> the compiler enforce "good programming style". Since there are differing
> views on such matters, it should be configurable in the form of a text file,
> and passed to the compiler as a command line parameter, i.e. something
> like "-style=<file>".
>

Make sure that anything like this can be disabled. It's bad enough
keeping track of what compiler writers think I can't be trusted to use
correctly to implement the standard library, without adding arbitrary
user conventions.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

Trevor L. Jackson, III

unread,
Mar 18, 2005, 8:13:47 AM3/18/05
to

A sizable fraction of the "features" of C++ are aimed at that goal.
Things like the inability to pass a temporary object to a non-const
reference have nothing to do with the expressive power of the language
and everything to do with attempting to prevent programmers from making
mistakes.

IMHO the entire effort is itself a mistake. One cannot make tools safer
without making them less capable -- in some cases much less capable.

/tj3

Carlos Moreno

unread,
Mar 19, 2005, 5:46:59 AM3/19/05
to
Trevor L. Jackson, III wrote:

>>Any comments, anyone?
>>Has there been any work done along these lines?
>
> A sizable fraction of the "features" of C++ are aimed at that goal.

And a considerable fraction is limited to *facilitate* good and safe
programming practices, and not to encourage them.

Another considerable fraction of the features does a little bit more:
it *encourages* good and safe practices.

But the OP's suggestion makes sense to me -- individual companies
have internal programming practices where certain practices are
required and certain other practices are forbidden.

Each individual entity has all the right to do as they please;
they own the code their programmers do, and they are the ones that
pay the programmers to code: they have the right to require their
programmers to do as they want.

Now, why would you oppose to a piece of software that simplifies
the task of enforcing whatever programming practices they want?

You (or I) are no-one to tell them what features they should use
and what they shouldn't.

> IMHO the entire effort is itself a mistake. One cannot make tools safer
> without making them less capable -- in some cases much less capable.

The thing is, less capable of what? Less capable of screwing up?
Are you unhappy because you're not capable of modifying an object
that has been declared const? (well, you *are* capable, of course,
but you'd have to go out of your way to do it).

Do you feel that you have to be capable of writing programs that
have only global variables, all with a one-letter name (two letters
maximum, and only if we need more than 52 variables), and that
use no functions and no classes/structs whatsoever?


Carlos
--

Pete Becker

unread,
Mar 19, 2005, 8:53:39 PM3/19/05
to
Carlos Moreno wrote:

>
> Now, why would you oppose to a piece of software that simplifies
> the task of enforcing whatever programming practices they want?
>

Because I have to write headers that compile in the environment that
someone else creates. It's hard enough to quiet warnings from six
different compiler vendors' notions of "good practice" (which sometimes
conflict). I can't imagine doing this for user-specifiable criteria.

Is someone wants to use lint they can use lint. It's not the compiler's job.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Trevor L. Jackson, III

unread,
Mar 19, 2005, 8:54:52 PM3/19/05
to
Carlos Moreno wrote:

Yes. And I do so. In assembler. When I need to write higher level
software I use a higher level language. C++, in spite of its
instability and logical lacunae is a good one.

That's not the issue. The issue is the safety belts that get in the way
of writing clear, correct code. A related issue is the interlocking of
what should be orthogonal aspects of the code.

Examples abound.

1.) Every translation unit is required to have at least one external
definition. That requirement gets in the way of code for scaffolding,
test harnesses and debugging. It gains users of the language *nothing*.

Translation units should be allowed to be empty. if you cannot handle
an empty translation unit, why should I believe you can handle one with
source in it?

2.) Templates must have a least one parameter (this one really surprised
me it is so stupid. A function template without parameters is just a
function. A class template without parameters is just a class. Why
doesn't C++ forbid functions without arguments? strings with no
characters? functions with no statements? statements with no
expressions?) The rule *creates* an unnecessary gap in the development
of good templates that even the designer of the language said should
begin with the design, implementation, and testing of non-templates.

Empty template argument lists should be supported. If you cannot handle
the zero case, why should I believe you can have the cases with one or more?

[the above two make me suspect someone does not understand that zero is
a legitimate number for expressing the count of elements of a linguistic
feature]

3.) Changing the writability of a variable alters the default linkage of
the object. This sounds like it was _designed_ to trip up programmers.
It *cannot* be justified by any amount of rationalization because
having a keyword silently change the default for an unrelated property
is *never* a good idea.

Adding or removing constness should not affect any other property of the
affected entity. Specifically, it should be possibly to remove all
const qualifiers from a const-correct program and have a correct program
with the same semantics. That is not currently possible.

4.) Objects with const members or with reference members must have a
constructor. Thus they cannot be PODs! These rules reinforce my
opinion that initialization has been neglected and even damaged during
the development of the standard.

Objects with const or reference members should not require constructors.
Failing to initialize an a const or reference member during the
creation of an object should be an error.

5.) Temporary objects cannot be bound to non-const references even when
it is appropriate to do so -- i.e., there is no override mechanism.

A mechanism to associate references with objects of any qualification is
necessary. See comment re const-correctness above.

6.) Constructors cannot call each other. This leads to very complex
work-arounds with private member functions and puts member
initialization in conflict with singularity of implementation. This
cannot be excused as necessary. It is just another case of unnecessary
inconsistency in the language.

A constructor should be able to invoke a sibling constructor in exactly
the same way as a constructor invokes a base class constructor.

Am I bashing C++? of course not. Am I criticizing the existing
standard? Damned right. But constructively.

Your "defense" of the standard was _not_ constructive. Nothing I said
had anything to do with writing BASIC in C++ as you suggested. So
either deal with the actual issues or waste your time harassing someone
else.

/tj3

M Jared Finder

unread,
Mar 19, 2005, 9:02:31 PM3/19/05
to

If I encounter a problem where making all variables global is the
cleanest and simplest solution, then yes, I do feel I should be capable
of writing programs that have only global variables.

A more realistic example would be a requirement like "never use raw
pointers -- always use safe pointers". What if I encounter a problem
where the cleanest solution would be to create a new type of safe
pointer, and use that? I *can't* create a new type of safe pointer
without using raw pointers, so I can't solve the problem. I'd be very
very wary of taking away capability without providing a simple (though
verbose) way of getting that power back. Look at C++'s reinterpret_cast
and const_cast. They provide a way to work around the compiler's type
system in unsafe ways, but they are there because they are *sometimes
needed*.

-- MJF

Joshua Lehrer

unread,
Mar 20, 2005, 4:03:03 AM3/20/05
to
Are you suggesting that you think one should be able to pass a
temporary by non-const reference? If something would be a mistake 99%
of the time, then why not forbit it, in the language, given that there
are easy workarounds for the other 1%?

joshua lehrer
factset research systems
NYSE:FDS

Ivan Vecerina

unread,
Mar 20, 2005, 4:05:19 AM3/20/05
to
"Pete Becker" <peteb...@acm.org> wrote:
>> Now, why would you oppose to a piece of software that simplifies
>> the task of enforcing whatever programming practices they want?
>
> Because I have to write headers that compile in the environment that
> someone else creates. It's hard enough to quiet warnings from six
> different compiler vendors' notions of "good practice"
> (which sometimes conflict).

Just out of curiosity: could you provide examples of conflicting
warnings you've had to find workarounds for?
(I've only ever had to test production code on 2, maybe 3 compilers)


Thank you,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

Carlos Moreno

unread,
Mar 20, 2005, 6:36:01 PM3/20/05
to
Trevor L. Jackson, III wrote:

> Your "defense" of the standard was _not_ constructive.

Who was defending the standard? Are you sure you're not confusing
me with someone else?

> Nothing I said
> had anything to do with writing BASIC in C++ as you suggested.

But what the OP was suggesting does -- I was using the "writing
BASIC in C++" as an example to defend what the OP was proposing,
and contradict/contest your statement that suggests that any
restriction in how you write code decreases the useability and
the power of the language.

As a general rule, yes, things tend to go more or less correlated
this way.

But the language does allow you to write BASIC in C++; if someone
gives me a tool *that I can configure to* allow me to prevent such
code to be written, I wouldn't complain; I wouldn't feel that
the power of the language has been crippled.

Now, if that tool always prevents me from using global variables
at all, then I would complain -- but the key element here is
something that was suggested by the OP: *configurability*. You
specify, perhaps through a configuration file, what set of features
you want to enforce.

My point keeps being: if I'm an employer, and I pay you (as an
example) for writing C++ code for me, I have all the right to
*order* you not to use a single global variable; and I do it,
by manually inspecting your code... Why opposing to a software
tool that would allow me to do it without having to manually
inspect the code?

If you have a good case for using one global variable in a very
particular situation, you would come in my office to try to
convince me, right? If you have a good case, you might convince
me and I would allow you to do it that one time without firing
you (:-)) -- same thing if we have the tool; if you have a
good case and convince me, then I would turn off that feature
in the configuration file of that hypothetical system to
accomodate for your global variable that you convinced me was
a sound idea.

Carlos
--

Carlos Moreno

unread,
Mar 20, 2005, 6:33:54 PM3/20/05
to
M Jared Finder wrote:
> Carlos Moreno wrote:
>
>>Trevor L. Jackson, III wrote:
>>
>>
>>>IMHO the entire effort is itself a mistake. One cannot make tools safer
>>>without making them less capable -- in some cases much less capable.
>>
>>The thing is, less capable of what? Less capable of screwing up?
>>Are you unhappy because you're not capable of modifying an object
>>that has been declared const? (well, you *are* capable, of course,
>>but you'd have to go out of your way to do it).
>>
>>Do you feel that you have to be capable of writing programs that
>>have only global variables, all with a one-letter name (two letters
>>maximum, and only if we need more than 52 variables), and that
>>use no functions and no classes/structs whatsoever?
>
>
> If I encounter a problem where making all variables global is the
> cleanest and simplest solution, then yes, I do feel I should be capable
> of writing programs that have only global variables.

Hmmm, no, sorry, this argument is, IMHO, too weak... The *if* is
too hypothetical and too unrealistic. But ok, we can still accept
this argument (see below), even though you kind of admit it yourself
that it is a bit unrealistic.

> A more realistic example would be a requirement like "never use raw
> pointers -- always use safe pointers". What if I encounter a problem
> where the cleanest solution would be to create a new type of safe
> pointer, and use that? I *can't* create a new type of safe pointer
> without using raw pointers, so I can't solve the problem. I'd be very
> very wary of taking away capability without providing a simple (though
> verbose) way of getting that power back. Look at C++'s reinterpret_cast
> and const_cast. They provide a way to work around the compiler's type
> system in unsafe ways, but they are there because they are *sometimes
> needed*.

Yes, I agree. And this does not contradict what the OP was suggesting
(at least not the way I interpreted it). You can always play with the
configuration file, or use a special configuration file for a particular
source file in which you have a good case to make an exception to the
rules that you established as a general policy.

Carlos
--

Carlos Moreno

unread,
Mar 20, 2005, 6:35:10 PM3/20/05
to
Pete Becker wrote:
> Carlos Moreno wrote:
>
>>Now, why would you oppose to a piece of software that simplifies
>>the task of enforcing whatever programming practices they want?
>
> Because I have to write headers that compile in the environment that
> someone else creates. It's hard enough to quiet warnings from six
> different compiler vendors' notions of "good practice" (which sometimes
> conflict). I can't imagine doing this for user-specifiable criteria.

I don't see this as an argument against such system; I see it more
like a reason why the compiler should disable all those validations
whenever it includes a standard library file (ok, perhaps it would
be a tough job for the compiler to keep track of that, but still).

Now, I'm not familiar with this lint -- if it is an external software
that does that job, then ok; I'm kind of defending the idea that the
OP suggested, regardless of whether it's the compiler or some other
piece of software that executes it. (and of course, provided that
standard library headers are excluded from such validation process)

Carlos
--

Pete Becker

unread,
Mar 20, 2005, 6:37:08 PM3/20/05
to
Ivan Vecerina wrote:
>
> Just out of curiosity: could you provide examples of conflicting
> warnings you've had to find workarounds for?

That was a bit of shorthand; sometimes rewriting code to eliminate a
warning from one compiler doesn't eliminate a similar warning from
another compiler, and you end up spending still more time finding a way
to rewrite legal, unambiguous, well-defined code in a way that makes
both compilers happy. I'm rarely rational on this subject. It is a pain
in the *** to have to write to the intersection of various random
notions of what constitutes "good programming style."

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Trevor L. Jackson, III

unread,
Mar 20, 2005, 6:39:37 PM3/20/05
to
Joshua Lehrer wrote:

> Are you suggesting that you think one should be able to pass a
> temporary by non-const reference?

I'm pretty sure I said so. If I did not say so previously, there I
hereby say so.

Of course it is a dangerous practice and should not be used routinely.
But when it is necessary it is necessary and the implementation should
not presume to dictate that it cannot be necessry. I would not mind and
would postively appreciate a warning/error diagnostic as the usual case.
But just as there are rare occasions in which a goto or a cast is the
proper solution to a problem, sometimes a non-const reference argument
needs to receive a temporatry argument.

Note that that last sentence distinguishes a specific case from the
general case of initializing references. The specific case is not
categorically wrong whereas the gmore general case of loose references
initialized with temporary objects is incorrect in almost every case.

But the simplistic rule against binding a temporary to a non-const
reference is defective because it does not make the fine distinctions
required to improve the language. The crudeness of the rule results in
a net decrease int he utility of the language. And it is unnecessary
because C++ is never going to be a "safe" language in which to write
code. Not ever.

> If something would be a mistake 99%
> of the time, then why not forbit it, in the language, given that there
> are easy workarounds for the other 1%?

Because I should not have to work around the language's "features". it
is in exactly those tricky or strange cases that clarity of code becomes
paramount. Contrived code is usually the symptom of bad design. In
these cases the defective design is not in the application, but in the
language itself.

There are lots of things that are bad programming practice that are not
and should not be forbidden. Any other approach is inconsistent with
the premise that the final responsibility for hte software lies with the
programmer rather than with the compiler.

If you want to design languages for use by people who don't know better
then go enhance Visual BASIC and leave the languages intended to be used
by people who do know better alone.

The last thing C++ programmers need is restrictions on their expressive
power "for their own good".

/tj3

Jonathan Turkanis

unread,
Mar 20, 2005, 6:52:03 PM3/20/05
to
Ivan Vecerina wrote:
> "Pete Becker" <peteb...@acm.org> wrote:
>>> Now, why would you oppose to a piece of software that simplifies
>>> the task of enforcing whatever programming practices they want?
>>
>> Because I have to write headers that compile in the environment that
>> someone else creates. It's hard enough to quiet warnings from six
>> different compiler vendors' notions of "good practice"
>> (which sometimes conflict).
>
> Just out of curiosity: could you provide examples of conflicting
> warnings you've had to find workarounds for?
> (I've only ever had to test production code on 2, maybe 3 compilers)

How about:

- function must return a value
- statement is unreachable

?

Jonathan

Pete Becker

unread,
Mar 20, 2005, 7:02:12 PM3/20/05
to
Carlos Moreno wrote:
> Pete Becker wrote:
>
>>Carlos Moreno wrote:
>>
>>
>>>Now, why would you oppose to a piece of software that simplifies
>>>the task of enforcing whatever programming practices they want?
>>
>>Because I have to write headers that compile in the environment that
>>someone else creates. It's hard enough to quiet warnings from six
>>different compiler vendors' notions of "good practice" (which sometimes
>>conflict). I can't imagine doing this for user-specifiable criteria.
>
>
> I don't see this as an argument against such system; I see it more
> like a reason why the compiler should disable all those validations
> whenever it includes a standard library file (ok, perhaps it would
> be a tough job for the compiler to keep track of that, but still).

The devil is in the details; "but still" doesn't banish him.

>
> Now, I'm not familiar with this lint

It's been the standard tool for reviewing code style for thirty years.


-- if it is an external software
> that does that job, then ok; I'm kind of defending the idea that the
> OP suggested, regardless of whether it's the compiler or some other
> piece of software that executes it.

The OP suggested "having the compiler enforce 'good programming style'".

> (and of course, provided that
> standard library headers are excluded from such validation process)
>

Not just standard library headers, but all third-party headers.

--

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Dave Harris

unread,
Mar 21, 2005, 2:01:48 AM3/21/05
to
usene...@lehrerfamily.com (Joshua Lehrer) wrote (abridged):

> Are you suggesting that you think one should be able to pass a
> temporary by non-const reference?

I think so.


> If something would be a mistake 99% of the time, then why not forbit
> it, in the language

In my view the problem cases are due to implicit conversions, so a rule
which disallowed implicit conversions when the target is a non-const
reference would prevent the 99% of errors. (I'd be interested in a good
counter-example.)


> given that there are easy workarounds for the other 1%?

The usual workaround is to introduce a named variable. This means figuring
out and hardwiring the type of the expression, and then thinking of a name
for the variable. It may mean introducing a scope. It reduces the general
expressiveness of the language. I'd much rather write:

x = -b + sqrt(b*b - 4*a*c)/(2*a);

than:

{
double b_squared = b*b;
double a_times_4 = 4*a;
double a_times_4_times_c = a_times_4 * c;
double diff = b_squared - a_times_4_times_c;
double sqrt_whatever = sqrt(diff);
double a_times_2 = a*2;
double sqrt_over_2_times_a = sqrt_whatever/a_times_2;
x = sqrt_over_2_times_a - b;
}

which gives you some idea of the gain in expressiveness we get from being
able to write full expressions without having to name intermediate
results.

-- Dave Harris, Nottingham, UK

David Abrahams

unread,
Mar 21, 2005, 2:04:05 AM3/21/05
to
Carlos Moreno <moreno_at_mo...@xx.xxx> writes:

> Pete Becker wrote:
>> Carlos Moreno wrote:
>>
>>>Now, why would you oppose to a piece of software that simplifies
>>>the task of enforcing whatever programming practices they want?
>>
>> Because I have to write headers that compile in the environment that
>> someone else creates. It's hard enough to quiet warnings from six
>> different compiler vendors' notions of "good practice" (which sometimes
>> conflict). I can't imagine doing this for user-specifiable criteria.
>
> I don't see this as an argument against such system; I see it more
> like a reason why the compiler should disable all those validations
> whenever it includes a standard library file (ok, perhaps it would
> be a tough job for the compiler to keep track of that, but still).

In addition to Pete's writing standard libraries, Pete and I both
write nonstandard libraries too, which have the same problem. I'm
probably more willing than Dinkumware to say "that warning's stupid;
if you don't like it, turn it off," but even so "stupid" warnings
cause similar problems for my code.

So, yeah: should you implement such a system, make sure there's an
in-code way to turn off these things!

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Antoun Kanawati

unread,
Mar 21, 2005, 2:04:42 AM3/21/05
to
Jonathan Turkanis wrote:
> Ivan Vecerina wrote:
>
>>"Pete Becker" <peteb...@acm.org> wrote:
>>
>>>>Now, why would you oppose to a piece of software that simplifies
>>>>the task of enforcing whatever programming practices they want?
>>>
>>>Because I have to write headers that compile in the environment that
>>>someone else creates. It's hard enough to quiet warnings from six
>>>different compiler vendors' notions of "good practice"
>>>(which sometimes conflict).
>>
>>Just out of curiosity: could you provide examples of conflicting
>>warnings you've had to find workarounds for?
>>(I've only ever had to test production code on 2, maybe 3 compilers)
>
>
> How about:
>
> - function must return a value
> - statement is unreachable
>
> ?

Good one!

Programming practices are, generally, rules of thumb that are highly
applicable in certain specific contexts. The problem of defining the
rules, with the proper context, capturing all the fine nuances of the
allowable exceptions, is a massive one.

So, without some extreme sophistication, all you have is an automated
nitpicking tool. Frankly, I'd rather leave that out of my compiler.

--
A. Kanawati
NO.anto...@comcast.net

Francis Glassborow

unread,
Mar 21, 2005, 11:09:42 AM3/21/05
to
In article <1Ef%d.9145$cQ3....@weber.videotron.net>, Carlos Moreno
<moreno_at_mo...@xx.xxx> writes

>Now, I'm not familiar with this lint

Then it is about time that you familiarised yourself with it. The task
of imposing cross translation unit validations and checking dangerous
practices lies firmly in the domain of such tools. I would not want to
work in a shop where such tools were not part and parcel of the process
of development.

> -- if it is an external software
>that does that job, then ok; I'm kind of defending the idea that the
>OP suggested, regardless of whether it's the compiler or some other
>piece of software that executes it. (and of course, provided that
>standard library headers are excluded from such validation process)

IMHO, it is the job of a compiler to compile code. Code analysis is the
task of other tools. If compilers did not try to make half-baked
attempts at being helpful, students would learn from early on that they
should use additional tools.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Mar 21, 2005, 11:10:32 AM3/21/05
to
In article <Fsf%d.1579$aQ.4...@wagner.videotron.net>, Carlos Moreno
<moreno_at_mo...@xx.xxx> writes

>My point keeps being: if I'm an employer, and I pay you (as an
>example) for writing C++ code for me, I have all the right to
>*order* you not to use a single global variable; and I do it,
>by manually inspecting your code... Why opposing to a software
>tool that would allow me to do it without having to manually
>inspect the code?

We aren't opposing the idea, only opposing that the Standard or the
compiler should be the tool to do it. There are a number of powerful
(some costly, some cheap) software tools that are designed to enforce
local coding standards as well as to detect potentially problematic
programming constructs.

Learning to use the correct tools reduces the desire to have a Swiss
Army knife and increases the awareness of the need for a complete
toolkit.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Llewelly

unread,
Mar 21, 2005, 11:20:45 AM3/21/05
to
Carlos Moreno <moreno_at_mo...@xx.xxx> writes:

> Pete Becker wrote:
>> Carlos Moreno wrote:
>>
>>>Now, why would you oppose to a piece of software that simplifies
>>>the task of enforcing whatever programming practices they want?
>>
>> Because I have to write headers that compile in the environment that
>> someone else creates. It's hard enough to quiet warnings from six
>> different compiler vendors' notions of "good practice" (which sometimes
>> conflict). I can't imagine doing this for user-specifiable criteria.
>
> I don't see this as an argument against such system; I see it more
> like a reason why the compiler should disable all those validations
> whenever it includes a standard library file

[snip]

I only know of one compiler which provides such a feature. And that
case, the feature is busted with respect to templates. Worse, the
documentation does not address the issue of whether it should be
used for third-party libraries. (Though it does seem to work for
3rd party libs.)

Ivan Vecerina

unread,
Mar 22, 2005, 4:30:08 AM3/22/05
to
"Andrei Alexandrescu (See Website for Email)"
<SeeWebsit...@moderncppdesign.com> wrote in message
news:423F432E...@moderncppdesign.com...
> Ivan Vecerina wrote:
>> That's a good one, and it does bring back some memories!
>>
>> int myFunction()
>> {
>> if( some inputs are ok )
>> return some_ok_value;
>>
>> throw some_error;
>> //return some dummy because "function must return a value" ?
>> }
>
> You could have written
>
> return throw some_error;

Not on the compiler that complained "function must return a value",
(MSVC6 I think), because it also rejected void returns ;)

The obvious fix was of course:
if( erroneous inputs )
throw some_error;
return some_ok_value;


Cheers,

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Allan W

unread,
Mar 22, 2005, 4:10:52 AM3/22/05
to
Michael Jørgensen wrote:
> Here is an idea I've been thinking about for a while: The idea is to
have
> the compiler enforce "good programming style".

Michael, let me answer this with a true story. I'll try not to make it
too long.

About 20 years ago I got a chance to expand my resume. I was going to
develop a new project using not one but three computer languages on a
client/server system. The PC front end would use mostly C, the back-end
mainframe would use an IBM fourth-generation language called CSP
(Cross-System Product, I kid you not), and the reports on the mainframe
would use COBOL.

The really exciting part was supposed to be CSP. I would be one of the
first people (in my organization, anyway) to learn this new language
that was certain to revolutionize the entire industry. The big selling
points about CSP were:

* Cross-system: the program worked exactly the same way on every
platform
* Fourth-generation: unlike messy languages like C and COBOL, it was
impossible to write a bad program in CSP.

Both of these claims turned out to be false.

* Because of IBM's claims, my bosses were assured that we could do
all
of our testing in TSO, so the bank I worked for never did give us
the
ability to test anywhere else. But there were several changes we
had
to make to get the program working properly in the CICS production
environment. Every time we missed one of these changes, our
program
bombed. (As far as I know, CSP was never implemented anywhere
except
TSO and CICS -- both IBM operating systems.) I could go on about
this,
but this isn't the part I think is relevant to what you asked.

* When IBM said it was "impossible to write a bad program in CSP",
what
they really meant was that the compiler would "enforce good
programming
style." This is the part that I think is relevant to answering
your
question. Here's how they enforced this:

- Every subroutine could have as many assignment statements (with
expressions) as needed. BUT

- Subroutines could only have ONE statement that did anything else
(I/O, IF, LOOP, etc).

So if I wanted to process a 2-dimensional array, I had to write the
outer loop in one function, and the body of that loop calls another
function... that second function would have the inner loop... if I
wanted to do something like display the array, I needed to have a third
function to do the WRITE statement. A very simple program had 80
functions, and 50 of them were one-line functions that in any other
language wouldn't have been a function at all.

CSP was the very first language where, even though I had experience
with it, I decided NOT to put on my resume. I figured, if a CSP
background helps me to get some job, I don't want that job.

> Any comments, anyone?

Offhand, I can't think of a single rule of style that there isn't
sometimes (once in a decade) some GOOD reason to break (other than
syntax errors).

- Never use recursion? There's another thread discussing this right
now. Sometimes recursion simplifies your code a lot, with no measurable
performance loss.

- Never put multiple statements on the same line? Sometimes statements
come in pairs. If they're both short and there are multiple sets that
are mostly identical, sometimes putting them on the same line can help
make the code more clear.

- Never use GOTOs? Avoid them most of the time, but sometimes they
simplify things a lot.

When I have a GOOD reason to break these rules, I'll defend them in a
code walk-through... but how do you argue with a compiler?

My main comment: Compiler-enforced good programming style -- Just Say
No!

Carlos Moreno

unread,
Mar 22, 2005, 6:11:22 PM3/22/05
to
Allan W wrote:

> When I have a GOOD reason to break these rules, I'll defend them in a
> code walk-through... but how do you argue with a compiler?

That one's easy: We have ways of arguing with a compiler; examples
of this are const_cast, reinterpret_cast, private and non-implemented
assignment operator or copy constructor, etc.

For the record, it has been already argued (and I have been convinced)
that such task is best left to other tools -- a compiler's job should
be to compile. My comment to your question would apply to either a
compiler enforcing rules or an external tool enforcing rules.

Carlos
--

Andrei Alexandrescu (See Website For Email)

unread,
Mar 22, 2005, 6:26:40 PM3/22/05
to
John Potter wrote:
> On 21 Mar 2005 21:02:17 -0500, "Andrei Alexandrescu (See Website for

> Email)" <SeeWebsit...@moderncppdesign.com> wrote:
>
>
>>Ivan Vecerina wrote:
>>
>>>That's a good one, and it does bring back some memories!
>>>
>>>int myFunction()
>>>{
>>> if( some inputs are ok )
>>> return some_ok_value;
>>>
>>> throw some_error;
>>> //return some dummy because "function must return a value" ?
>>>}
>
>
>>You could have written
>
>
>>return throw some_error;
>
>
> Nope. The throw has type void and the function return type is int.
> That would be accepted if the return type were void; however, there
> would be no need for the return in that case.

That's funny. I thought a throw expression could be substituted for any
type, as in:

return a ? 1 : throw "whatever";

However, if I wrote:

int test() {
return throw 1;
}

I got an error. But when I wrote:

int test(int x) {
return x ? 1 : throw 1;
}

What's going on?


Andrei

Trevor L. Jackson, III

unread,
Mar 22, 2005, 4:16:13 AM3/22/05
to
Nicola Musatti wrote:
> Trevor L. Jackson, III wrote:
> [...]

>
>>Objects with const or reference members should not require
>
> constructors.
>
>> Failing to initialize an a const or reference member during the
>>creation of an object should be an error.
>
>
> How do you expect to perform such initialization if your const or
> reference member is private and you do not provide a constructor? Or
> are you just thinking of classes with public members only, to be
> initialized with the
> = {...} syntax?

I never said anything about private members. I was referring to PODs.
In fact it gets worse than that. I cannot default initialize a const
object, even a builtin because "const objects must be initialized".

int const zero; // initialization failure!

> The right way to deal with this is to move the relevant data members to
> a private base class.

No, that it not the right way to deal with this. The right way to deal
with this is to have the language support clarity by not mandating
work-arounds for it features.

> I'm convinced that forwarding constructors are a
> bad idea and will prove to be more a source of errors than a help.

Why is calling a sibling contructor a problem where calling a base class
constructor is not?

Dave Harris

unread,
Mar 22, 2005, 6:36:42 PM3/22/05
to
jpo...@lhup.edu (John Potter) wrote (abridged):
> Please show us an example of a function which modifies its reference
> parameter where it would be good to allow temporaries.

A classic is:

v.swap( vector<int>() );

Another is visitor code like:

tree->accept( MyVisitor() );

Another case is where a function does something and returns information,
and the client doesn't care about the information. There's a long
tradition of ignoring results in C/C++, eg consider the result of printf.

highlight( Rect( 0,0,100,100 ) );

Another case is where I was implementing a move/pilfer mechanism:

e = a + b + c;

where the result of (a+b) is a temporary object which I wanted to reuse to
store (a+b+c).

Another case is where the function just wants some buffer space. Passing
the space in lets it be reused without being reallocated, but if we don't
need it to be reused we should be able to pass in a temporary.

I don't know, it just seems obvious to me. Whether an object can be bound
to a non-const reference should be orthogonal to whether that object has a
name. They are unrelated concepts.

-- Dave Harris, Nottingham, UK

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Carlos Moreno

unread,
Mar 22, 2005, 4:23:37 AM3/22/05
to
John Potter wrote:

>> x = -b + sqrt(b*b - 4*a*c)/(2*a);
>

> I suspect you would rather write the correct quadradic formula than
> that.

As I suspect that you'd rather write quadratic? :-)

Strange, huh? The typical oversight in that sort of situation goes
more like (-b ..... ) / 2*a


> Please show us an example of a function which modifies its reference
> parameter where it would be good to allow temporaries.

I'll play the devil's advocate:

void draw_rotated (Shape & s)
{
s.rotate (pi/2);
s.draw();
}

Knowing what that function does, you might want to pass it a
temporary -- in such case, it seems natural that the rotation
only served the purpose of displaying the shape rotated, and
that you won't use the shape afterwards so you don't care if
it was modified or not by the function.

Of course, you could definitely accuse the above of extremely
poor design -- a single function is performing two separate
tasks.

Carlos
--

M Jared Finder

unread,
Mar 22, 2005, 4:25:48 AM3/22/05
to
Andrei Alexandrescu (See Website for Email) wrote:
> Ivan Vecerina wrote:
>
>>That's a good one, and it does bring back some memories!
>>
>>int myFunction()
>>{
>> if( some inputs are ok )
>> return some_ok_value;
>>
>> throw some_error;
>> //return some dummy because "function must return a value" ?
>>}
>
>
> You could have written
>
> return throw some_error;

Throw returns an int (syntactically)? I thought throw returned nothing.

-- MJF

John Potter

unread,
Mar 22, 2005, 4:16:43 AM3/22/05
to
On 21 Mar 2005 21:02:17 -0500, "Andrei Alexandrescu (See Website for
Email)" <SeeWebsit...@moderncppdesign.com> wrote:

> Ivan Vecerina wrote:
> > That's a good one, and it does bring back some memories!
> >
> > int myFunction()
> > {
> > if( some inputs are ok )
> > return some_ok_value;
> >
> > throw some_error;
> > //return some dummy because "function must return a value" ?
> > }

> You could have written

> return throw some_error;

Nope. The throw has type void and the function return type is int.


That would be accepted if the return type were void; however, there
would be no need for the return in that case.

John

Seungbeom Kim

unread,
Mar 22, 2005, 6:44:18 PM3/22/05
to
Trevor L. Jackson, III wrote:

> 1.) Every translation unit is required to have at least one external
> definition. That requirement gets in the way of code for scaffolding,
> test harnesses and debugging. It gains users of the language *nothing*.

I'm surprised to hear that. Even Comeau C++ allows empty translation
units.. Where in the Standard is it stated?

> 3.) Changing the writability of a variable alters the default linkage of
> the object. This sounds like it was _designed_ to trip up programmers.
> It *cannot* be justified by any amount of rationalization because
> having a keyword silently change the default for an unrelated property
> is *never* a good idea.
>
> Adding or removing constness should not affect any other property of the
> affected entity. Specifically, it should be possibly to remove all
> const qualifiers from a const-correct program and have a correct program
> with the same semantics. That is not currently possible.

You have a point here, and orthogonality is a good idea in general, but
this is a complicated issue. Const was designed to replace #define, and
therefore it was necessary to treat const as a constant expression.

const int max = 14;

int a[max + 1];
switch (i) { case max: /* ... */; }

Removing const here breaks this valid code.

I understand the change of the default linkage as promoting the use of
const instead of #define. Specifically with respect to the linkage issue,
I agree that programmers could equally easily have written "static const"
instead of "const", but I understand that full orthogonality in general
was hard to achieve.

Can you suggest another good way of replacing #define'd symbols?

> 4.) Objects with const members or with reference members must have a
> constructor. Thus they cannot be PODs!

Can you point the relevant clause in the standard, please?

> Objects with const or reference members should not require constructors.
> Failing to initialize an a const or reference member during the
> creation of an object should be an error.

I tend to agree. I feel that "const int i; cout << i;" is just as wrong as
"int i; cout << i;", no more.

> 5.) Temporary objects cannot be bound to non-const references even when
> it is appropriate to do so -- i.e., there is no override mechanism.
>
> A mechanism to associate references with objects of any qualification is
> necessary. See comment re const-correctness above.

I strongly agree. It does makes sense to forbid bounding to a non-const
reference a temporary created through implicit conversion (as in

void incr(int& rr) { rr++; }
double ss = 1;
incr(ss);

), but not to forbid it for all temporaries. I find it very frustrating
and annoying to have to write

bool extract(std::istream& is, int& i) { return is >> i; }

std::string s("123"); int i;
std::istringstream is(s);
extract(is, i);
// "is" not needed any more

instead of

bool extract(std::istream& is, int& i) { return is >> i; }

std::string s("123"); int i;
extract(std::istringstream(s), i);

and

bool test_run(game_state &);

game_state g1(...);
if (!test_run(g1)) return false; // "g1" not needed any more
game_state g2(...);
if (!test_run(g2)) return false; // "g2" not needed any more
game_state g3(...);
if (!test_run(g3)) return false; // "g3" not needed any more

instead of

bool test_run(game_state &);

if (!test_run(game_state(...))) return false;
if (!test_run(game_state(...))) return false;
if (!test_run(game_state(...))) return false;

Having to write a common idiom "ostringstream().flush() << ..." instead of
"ostringstream() << ..." is counter-intuitive enough.

Binding a temporary to a non-const reference should be prohibited only
when the temporary is from an implicit conversion.

References:
http://groups.google.com/groups?selm=bd47bb0e.0304202334.5077c375%40posting.google.com
http://groups.google.com/groups?selm=d6651fb6.0212310632.61852afc%40posting.google.com

--
Seungbeom Kim

Gerhard Menzl

unread,
Mar 22, 2005, 5:43:50 PM3/22/05
to
Andrei Alexandrescu wrote:

> Ivan Vecerina wrote:
>
>>int myFunction()
>>{
>> if( some inputs are ok )
>> return some_ok_value;
>>
>> throw some_error;
>> //return some dummy because "function must return a value" ?
>>}
>
>
> You could have written
>
> return throw some_error;

But would it have compiled? The type of a throw-expression is void,
hence the trick works only for functions that return void.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

Seungbeom Kim

unread,
Mar 23, 2005, 5:08:31 AM3/23/05
to
Andrei Alexandrescu (See Website For Email) wrote:

> That's funny. I thought a throw expression could be substituted for any
> type, as in:
>
> return a ? 1 : throw "whatever";
>
> However, if I wrote:
>
> int test() {
> return throw 1;
> }
>
> I got an error.

Because a throw-expression is of type void (15/1).

> But when I wrote:
>
> int test(int x) {
> return x ? 1 : throw 1;
> }

This is okay because it is specifically allowed for the conditional
operator (5.16/2):

If either the second or the third operand has type (possibly cv-qualified)
void, then the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and
function-to-pointer (4.3) standard conversions are performed on the second
and third operands, and one of the following shall hold:
— The second or the third operand (but not both) is a throw-expression
(15.1); the result is of the type of the other and is an rvalue.
— Both the second and the third operands have type void; the result is of
type void and is an rvalue. [Note: this includes the case where both
operands are throw-expressions.]

--
Seungbeom Kim

Trevor L. Jackson, III

unread,
Mar 23, 2005, 5:12:13 AM3/23/05
to
Seungbeom Kim wrote:
> Trevor L. Jackson, III wrote:

>>3.) Changing the writability of a variable alters the default linkage of
>>the object. This sounds like it was _designed_ to trip up programmers.
>> It *cannot* be justified by any amount of rationalization because
>>having a keyword silently change the default for an unrelated property
>>is *never* a good idea.
>>
>>Adding or removing constness should not affect any other property of the
>>affected entity. Specifically, it should be possibly to remove all
>>const qualifiers from a const-correct program and have a correct program
>>with the same semantics. That is not currently possible.
>
>
> You have a point here, and orthogonality is a good idea in general, but
> this is a complicated issue. Const was designed to replace #define, and
> therefore it was necessary to treat const as a constant expression.

Actually it was not necessary. It may have been desirable from a
particular perspective, but that perspective permits a particular agenda
to distort the language overall. That's a Bad Thing(tm) no matter how
strongly the perspective is promoted.

>
> const int max = 14;
>
> int a[max + 1];
> switch (i) { case max: /* ... */; }
>
> Removing const here breaks this valid code.
>
> I understand the change of the default linkage as promoting the use of
> const instead of #define. Specifically with respect to the linkage issue,
> I agree that programmers could equally easily have written "static const"
> instead of "const", but I understand that full orthogonality in general
> was hard to achieve.

It is _not_ hard to achieve. It is hard to achieve in combination with
the special anti-#define agenda item.

>
> Can you suggest another good way of replacing #define'd symbols?

First, there is no need to replace #define symbols. The most that would
be useful would be to warn when a symbol is defined in lower or mixed case.

Second, "int const name = (expr);" serves quite well. The compiler can
do all of the same optimizations that it could if the declaration were
"static int const name = (expr);"

Third, screwing up const correctness is a _big_ problem. One that
cannot be justified by any kind of rationalization based on good
intentions. After all, the language has to be taught. And retained.
The more special exceptions it has the less utility it has as a general
purpose programming language.

>
>
>>4.) Objects with const members or with reference members must have a
>>constructor. Thus they cannot be PODs!
>
>
> Can you point the relevant clause in the standard, please?

I will have to find something to that effect.

I would not go that far. My understanding of the issue is based on the
classification of temporaries bound to named references and implicit or
explicit temporaries passed as function arguments. For example, passing
an expression to a non-const reference parameter is probably a problem
in that the temporary is implicit in the evaluation of the expression.
But passing an explicitly invoked ctor to a non-const reference
parameter is a useful idiom.

ISTM your examples re implicit conversions are subsets of the larger
category of expression evaluation. I find it interesting that the issue
that motivated me to make the comment was the need to circumvent the
rule in order to pass an explicitly constructed stream from a char const
*, which is almost exactly the issue you described in detail above.

I am not willing to express an opinion about expressions assigned to
non-argument, non-const references. I have not found the need to do
that but cannot claim there is no reason to do so.

/tj3

John Potter

unread,
Mar 23, 2005, 5:10:04 AM3/23/05
to
On 22 Mar 2005 18:26:40 -0500, "Andrei Alexandrescu (See Website For
Email)" <SeeWebsit...@moderncppdesign.com> wrote:

> However, if I wrote:

> int test() {
> return throw 1;
> }

> I got an error. But when I wrote:

> int test(int x) {
> return x ? 1 : throw 1;
> }

> What's going on?

Special case. See 5.16. See 15/1 for the type of throw-expression.

John

Carlos Moreno

unread,
Mar 23, 2005, 5:19:16 AM3/23/05
to
Dave Harris wrote:

>>Please show us an example of a function which modifies its reference
>>parameter where it would be good to allow temporaries.
>
> A classic is:
>
> v.swap( vector<int>() );

Very nice!! I have always found extremely unnatural having to
type vector<int>().swap (v).

OTOH, either way can (and should) be accused of being a hideous
and grotesque hack: a fragment of code should do exactly what
it does, and not some other action that comes indirectly as a
consequence -- if a statement says swap, it should be because
the sought effect is swapping two things, and not because you
want to clear a vector guaranteeing that memory is released.
*ugh*!!!

Carlos
--

Gerhard Menzl

unread,
Mar 23, 2005, 12:22:05 PM3/23/05
to
Andrei Alexandrescu (See Website For Email) wrote:

> That's funny. I thought a throw expression could be substituted for
> any type, as in:

Not according to 15/1: "A throw-expression is of type void".

> return a ? 1 : throw "whatever";
>
> However, if I wrote:
>
> int test() {
> return throw 1;
> }
>
> I got an error. But when I wrote:
>
> int test(int x) {
> return x ? 1 : throw 1;
> }
>
> What's going on?

The way I understand the standard, the first example works because of a
special rule for the conditional operator, which allows either the
second or the third operand to be of type void, in which case the result
is of the other operand's type (see 5.16/2). No such rule applies when
simply returning a throw-expression.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nicola Musatti

unread,
Mar 23, 2005, 12:23:37 PM3/23/05
to

Trevor L. Jackson, III wrote:
> Nicola Musatti wrote:
[...]

>> The right way to deal with this is to move the relevant data
members to
>> a private base class.
>
> No, that it not the right way to deal with this. The right way to
deal
> with this is to have the language support clarity by not mandating
> work-arounds for it features.

You can't really expect the language to simplify a convoluted design,
can you?. Initialization in a constructor is about dealing with members
one at a time; if you need to handle a subset of them together the
right tool is a class.

>> I'm convinced that forwarding constructors are a
>> bad idea and will prove to be more a source of errors than a help.
>
> Why is calling a sibling contructor a problem where calling a base
class
> constructor is not?

Because the inheritance relationship imposes an ordering that helps
keep things clear: you'll never be able to call the derived class
constructor first, so you don't have to worry about it. Not so with
forwarding constructors; at best you'll have to introduce arbitrary and
hard to understand limitations on their use, at worst every constructor
will have to be coded keeping in mind that it may be called either
before or after other constructors.

And what about destruction order, both in normal conditions and during
stack unwinding?

Cheers,
Nicola Musatti

Nicola Musatti

unread,
Mar 23, 2005, 12:24:21 PM3/23/05
to
But are these examples worth the risk of having references bind
temporaries created under your nose by automatic conversions? Note that
if I had my way I'd rather get rid of automatic conversions, but
somehow I don't think it's going to happen...

Cheers,
Nicola Musatti

Peter C. Chapin

unread,
Mar 23, 2005, 12:26:19 PM3/23/05
to
Carlos Moreno <moreno_at_mo...@xx.xxx> wrote in news:wDU%
d.37301$aQ.9...@wagner.videotron.net:

> For the record, it has been already argued (and I have been convinced)
> that such task is best left to other tools -- a compiler's job should
> be to compile.

Let me jump in with a quick comment. I agree that one should use
external tools rather than the compiler to enforce "metaproperties" of
programs such as style issues. However, some language features (or
misfeatures) complicate the creation of such tools.

For example, the horrendous syntax of C++ makes parsing C++ accurately
rather difficult. This inhibits tool builders. Since the compiler is
already doing the heavily lifting of parsing it is natural to look to
the compiler to do a lot of this other analysis as well. If C++ had a
simple and flexible design (hmmm... maybe like C?) one could more
realistically expect tools to step in and pick up the slack. As an
example, splint effectively allows you to create abstract data types in
C where the tool flags functions that are accessing the "private"
section of the type inappropriately.

Obviously the syntactic issues of C++ are not likely to go away any time
soon. But there are other aspects of the language that appear to make it
more flexible but that might make tool construction hard (and thus in
the long run actually detract from the power of the language). The
unrestrained use of goto is one possibile candidate for such feature.

Peter

Nicola Musatti

unread,
Mar 23, 2005, 12:49:55 PM3/23/05
to

Seungbeom Kim wrote:
[...]

> You have a point here, and orthogonality is a good idea in general,
but
> this is a complicated issue. Const was designed to replace #define,
and
> therefore it was necessary to treat const as a constant expression.
>
> const int max = 14;
>
> int a[max + 1];
> switch (i) { case max: /* ... */; }
>
> Removing const here breaks this valid code.
>
> I understand the change of the default linkage as promoting the use
of
> const instead of #define. Specifically with respect to the linkage
issue,
> I agree that programmers could equally easily have written "static
const"
> instead of "const", but I understand that full orthogonality in
general
> was hard to achieve.
>
> Can you suggest another good way of replacing #define'd symbols?

One alternative might be what we could call symbolic literals:

inline [int] max = 14;

A typed, scope aware compile time expression for which no memory is
allocated. The type specification could be made optional or omitted
completely, as the type of the symbolic literal can be inferred from
that of the expression.

Cheers,
Nicola Musatti

Frank Birbacher

unread,
Mar 23, 2005, 5:46:35 PM3/23/05
to
Hi!

Francis Glassborow wrote:
> IMHO, it is the job of a compiler to compile code. Code analysis is the
> task of other tools. If compilers did not try to make half-baked
> attempts at being helpful, students would learn from early on that they
> should use additional tools.

I'd rather prefer the same program for parsing the source in both
cases the style checking and code generation. If there are many
programs which need to somehow interpret/understand source code
then there are many programs which need to catch up on the standard.
Is there anything wrong with compilers allowing for style
checking?

Frank

Trevor L. Jackson, III

unread,
Mar 23, 2005, 5:58:16 PM3/23/05
to
Nicola Musatti wrote:

> Trevor L. Jackson, III wrote:
>
>>Nicola Musatti wrote:
>
> [...]
>
>>>The right way to deal with this is to move the relevant data
>
> members to
>
>>>a private base class.
>>
>>No, that it not the right way to deal with this. The right way to
>
> deal
>
>>with this is to have the language support clarity by not mandating
>>work-arounds for it features.
>
>
> You can't really expect the language to simplify a convoluted design,
> can you?. Initialization in a constructor is about dealing with members
> one at a time;

Oh really? Why is that? And where is that? There is no real advantage
to mandating that members, by which I assume you improperly means to
include base classes, be dealt with individually. In fact theer are
serious disadvantages to that approach. One is that it often leads to
code duplicattion. Another is the temptation to introduce an artificial
abstraction in the handling of members only for the purposes of
initialization.

> if you need to handle a subset of them together the
> right tool is a class.

I disagree. Quite strongly. Your statement depends upon the assumption
that the various sets of members can be arranged into a sequence of
proper subsets. That assumption isn't always true. If the members A
and B ned to be initialized in one instance and the members B and C
needs to be initializaed in another instance, should I multiply inherit
from parents classes AB and BC each of which inherit from virtual class
B (which is a wrapper for a built-in type)? I'm not going to do that,
nor let any of my coders do that.

What was it you were saying about simplifying a convoluted design?

Recursive placement new based on partial ctors (each of which manages
only a fraction of the full collection of members) is far superior
because they all appear together and the design can be clearly explained
in one a single place within the code.

>
>
>>>I'm convinced that forwarding constructors are a
>>>bad idea and will prove to be more a source of errors than a help.
>>
>>Why is calling a sibling contructor a problem where calling a base
>
> class
>
>>constructor is not?
>
>
> Because the inheritance relationship imposes an ordering that helps
> keep things clear: you'll never be able to call the derived class
> constructor first, so you don't have to worry about it. Not so with
> forwarding constructors; at best you'll have to introduce arbitrary and
> hard to understand limitations on their use, at worst every constructor
> will have to be coded keeping in mind that it may be called either
> before or after other constructors.

The ordering you seek should be derived from the ordering of the
declarations of the constructors. Any other rule leads to the
possibility of mutual recursion during initialization, and init lists
are not places I want to see stack checking.

But what is the worst thing that can happen? Someone writes a group of
ctors with a circular set of references. How is this badder (a
technical term) than permitting coders to write functions with a
circular set of references? Ctor init lists and calls to sibling ctors
can be just as conditional as mutual recursion or self recusrsion in
normal functions.

Self-recursion does not appear to be useful for ctors, but even today
you can put a call to a ctor in its own init list without violating the
standard. Why should that change?

>
> And what about destruction order, both in normal conditions and during
> stack unwinding?

Destruction order is determined by membership declaration order.
Constructors have no influence upon destruction. So I do not understand
the question. Can you amplify it?

/tj3

Gerhard Menzl

unread,
Mar 23, 2005, 5:53:41 PM3/23/05
to
Trevor L. Jackson, III wrote:

> First, there is no need to replace #define symbols. The most that
> would be useful would be to warn when a symbol is defined in lower or
> mixed case.

Just as there is no need for a language beyond C, which is
Turing-complete, after all. But there is - at least - one very good
reason for replacing preprocessor constants with something that is part
of the language rather than a directive for a primitive text conversion
utility: const variables respect scope, preprocessor constants don't.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Trevor L. Jackson, III

unread,
Mar 23, 2005, 6:04:38 PM3/23/05
to
Nicola Musatti wrote:

I like that approach. It is quite elegant.

> The type specification could be made optional or omitted
> completely, as the type of the symbolic literal can be inferred from
> that of the expression.

That flexibility is dangerous. I prefer typed literal constants. The
thing I miss most about C -> C++ is the loss of the limitation of NULL
as being a pointer. I see far too much code of the form:

while ( *str++ != NULL )
/* what did the author think he was doing? */
/* is the dereference an error? */
/* does he mean ASCII NUL rather than C's (void*)0? */
;

In C I can correct the problem. In C++ the miscreants point out that it
is perfectly legitimate code and that I should leave them alone. And
they are right.

So let us avoid typeless constants in order suppress promiscuous
conversions that silently cause miscommunication between the coder and
the compiler.

/tj3

Trevor L. Jackson, III

unread,
Mar 24, 2005, 6:53:18 AM3/24/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>First, there is no need to replace #define symbols. The most that
>>would be useful would be to warn when a symbol is defined in lower or
>>mixed case.
>
>
> Just as there is no need for a language beyond C, which is
> Turing-complete, after all. But there is - at least - one very good
> reason for replacing preprocessor constants with something that is part
> of the language rather than a directive for a primitive text conversion
> utility: const variables respect scope, preprocessor constants don't.

I suspect you need to choose your verb more carefully. You said
replace, which implies the addition of a new facility and the removal of
the existing facility. That's probably a mistake.

The addition of a new facility is perfectly reasonable, so long as it
does not trigger silliness like the change in linkage given to const
objects.

But the addition of a new facility does not require the removal of the
existing facility, so the use of the terms replace and replacement are
probably misleading and overstate the case.

/tj3

Trevor L. Jackson, III

unread,
Mar 24, 2005, 6:54:08 AM3/24/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>First, there is no need to replace #define symbols. The most that
>>would be useful would be to warn when a symbol is defined in lower or
>>mixed case.
>
>
> Just as there is no need for a language beyond C, which is
> Turing-complete, after all. But there is - at least - one very good
> reason for replacing preprocessor constants with something that is part
> of the language rather than a directive for a primitive text conversion
> utility: const variables respect scope, preprocessor constants don't.

Separate topic: proprocessor symbols can be turned off via #undef while
language declarations cannot. So the statement that preprocessor
directive do not respect scope is incorrect. Some do and some do not.
It depends upon the manning in which the symbols are used.

OTOH, language declarations _only_ repect scope, and there are times
that it is not convenient or even possible to establish a scope boundary
to terminate a language declaration.

When I can untypedef a symbol, or unint a variable name, I will believe
that language declarations are universally superior to preprocessor symbols.

/tj3

John Potter

unread,
Mar 24, 2005, 6:59:31 AM3/24/05
to
On 22 Mar 2005 18:36:42 -0500, bran...@cix.co.uk (Dave Harris) wrote:

> I don't know, it just seems obvious to me. Whether an object can be bound
> to a non-const reference should be orthogonal to whether that object has a
> name. They are unrelated concepts.

That is an amusing contradiction in C++. Objects without a name do not
have an identity, address. It seems obvious to me that allowing member
function calls with a this pointer and binding to const references are
the illogical things.

Anyway, the history is that it was allowed, found to be a problem and
removed from the language. The most good for the largest group is
likely to survive.

John

M Jared Finder

unread,
Mar 24, 2005, 6:59:09 AM3/24/05
to

I was following you up until the last sentence. First, how is goto
"unrestrained"? Second, how does this unrestrained-ness make tool
construction hard? I don't see how the program flow introduced by goto
is any more complicated than the program flow introduced by while.

-- MJF

Nicola Musatti

unread,
Mar 24, 2005, 7:02:01 AM3/24/05
to
Trevor L. Jackson, III wrote:
> Nicola Musatti wrote:
[...]

>>One alternative might be what we could call symbolic literals:
>>
>>inline [int] max = 14;
>>
>>A typed, scope aware compile time expression for which no memory is
>>allocated.
>
> I like that approach. It is quite elegant.
>
>>The type specification could be made optional or omitted
>>completely, as the type of the symbolic literal can be inferred from
>>that of the expression.
>
> That flexibility is dangerous. I prefer typed literal constants.
[...]

> So let us avoid typeless constants in order suppress promiscuous
> conversions that silently cause miscommunication between the coder and
> the compiler.

I wasn't suggesting that my symbolic literals be typeless. Rather, their
types could be inferred from the expression used to initialise them.
Still, I do prefer types to be explicitly specified.

Cheers,
Nicola Musatti

Francis Glassborow

unread,
Mar 24, 2005, 9:17:07 AM3/24/05
to
In article <KoqdnZ5F_Pi...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>Self-recursion does not appear to be useful for ctors, but even today
>you can put a call to a ctor in its own init list without violating the
>standard. Why should that change?

No you cannot, there is a proposal from Herb Sutter and myself to allow
something like this but it is not allowed in the current standard.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Gerhard Menzl

unread,
Mar 24, 2005, 9:21:11 AM3/24/05
to
Trevor L. Jackson, III wrote:

> I disagree. Quite strongly. Your statement depends upon the
> assumption that the various sets of members can be arranged into a
> sequence of proper subsets. That assumption isn't always true. If
> the members A and B ned to be initialized in one instance and the
> members B and C needs to be initializaed in another instance, should I
> multiply inherit from parents classes AB and BC each of which inherit
> from virtual class B (which is a wrapper for a built-in type)? I'm
> not going to do that, nor let any of my coders do that.

I have a hard time imagining a concrete example for a class where
different instances initialize different members. Call me naive, but my
classes always have their instances initialize all members. Or are you
talking about different subclasses? An example would be most helpful.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Alf P. Steinbach

unread,
Mar 24, 2005, 9:51:03 AM3/24/05
to
* Nicola Musatti:

>
> I wasn't suggesting that my symbolic literals be typeless. Rather, their
> types could be inferred from the expression used to initialise them.
> Still, I do prefer types to be explicitly specified.

I just posted in clc++ about a really ugly solution to the problem of
specifying string literals in char/wchar_t-agnostic template code.

Might as well repeat it here, as an argument _against_ typed literals
(untested code, seems to work):


======================================================================
#include <string>

struct dummy_type {};

template< template<typename Char> class LiteralStringDefiner >
struct cameleon_string_
{
operator char const* () const { return LiteralStringDefiner<char>::s; }
operator wchar_t const* () const { return LiteralStringDefiner<wchar_t>::s; }
};

#define DEFINE_CAMEL( name, literal_string ) \
namespace literal \
{ \
template< typename Dummy> struct name ## _char { static char const s[]; }; \
template< typename Dummy> char const name ## _char<Dummy>::s[] = "s"; \
\
template< typename Dummy> struct name ## _wchar_t { static wchar_t const s[]; };\
template< typename Dummy> wchar_t const name ## _wchar_t<Dummy>::s[] = L"s"; \
\
template< typename Char> struct name ## _; \
\
template<> struct name ## _<char>: name ## _char<dummy_type> {}; \
template<> struct name ## _<wchar_t>: name ## _wchar_t<dummy_type> {}; \
\
typedef cameleon_string_<name ## _> name; \
}

DEFINE_CAMEL( huh, "huh" )

template< typename Char >
void display( Char const* )
{
}

template< typename Char >
bool is_password( std::basic_string<Char> const& s )
{
display<Char>( literal::huh() );
return s == literal::huh_<Char>::s;
}

int main()
{
is_password<char>( "huh" );
is_password<wchar_t>( L"huh" );
}
======================================================================


This replaced or comes in addition to the simpler

struct literal_string
{
wchar_t const* myWide;
char const* myNarrow;

literal_string( wchar_t const* w, char const* n )
: myWide( w ), myNarrow( n )
{}

operator wchar_t const* () const { return myWide; }
operator char const* () const { return myNarrow; }
};

#define S( a ) literal_string( L ## a, a )

Anyway, all this would be unnecessary if we had untyped (or more
precisely meta-typed) literals, like I seem to recall that Pascal had.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Dave Harris

unread,
Mar 24, 2005, 9:51:46 AM3/24/05
to
nicola....@gmail.com (Nicola Musatti) wrote (abridged):

> But are these examples worth the risk of having references bind
> temporaries created under your nose by automatic conversions?

No. That's why I started by saying that shouldn't happen.


> Note that if I had my way I'd rather get rid of automatic
> conversions, but somehow I don't think it's going to happen...

That's a bigger change than I advocated. I think it's enough to suppress
implicit conversions when the target is a non-const reference. I don't
think this would break any existing code.

-- Dave Harris, Nottingham, UK

Trevor L. Jackson, III

unread,
Mar 24, 2005, 7:58:30 PM3/24/05
to
Francis Glassborow wrote:
> In article <KoqdnZ5F_Pi...@comcast.com>, "Trevor L. Jackson,
> III" <tl...@comcast.net> writes
>
>>Self-recursion does not appear to be useful for ctors, but even today
>>you can put a call to a ctor in its own init list without violating the
>>standard. Why should that change?
>
>
> No you cannot, there is a proposal from Herb Sutter and myself to allow
> something like this but it is not allowed in the current standard.

A clarification is in order. It may or may not be acceptable to have a
ctor appear, bare, in it's own or a sibling's init list. The lack of
ctor return values and the fact that init lists are just expressions
discourages the practice as much as anything else. However, it is
certainly possible to put a call to a constructor in a member function,
and that member function can be invoked in that or another ctor's init
list. If the inner ctor is a placement new usage then you get the
effect of sibling ctors indirectly.

Is it your position that the above-described usage violates the standard?

/tj3

Trevor L. Jackson, III

unread,
Mar 24, 2005, 8:07:07 PM3/24/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>I disagree. Quite strongly. Your statement depends upon the
>>assumption that the various sets of members can be arranged into a
>>sequence of proper subsets. That assumption isn't always true. If
>>the members A and B ned to be initialized in one instance and the
>>members B and C needs to be initializaed in another instance, should I
>>multiply inherit from parents classes AB and BC each of which inherit
>>from virtual class B (which is a wrapper for a built-in type)? I'm
>>not going to do that, nor let any of my coders do that.
>
>
> I have a hard time imagining a concrete example for a class where
> different instances initialize different members. Call me naive, but my
> classes always have their instances initialize all members. Or are you
> talking about different subclasses? An example would be most helpful.

It would take several pages in order to provide a concrete example that
could not be criticized as contrived. But consider an abstract example
based on the C++ streams library. In a tight memory situation one might
forgo the variations of (i/o/io)(' '/f/str/string)streams and provide a
single, unified IO model whose ctors managed the appropriate subset of
the unified class' functionality. Yes, a decomposition into separate
distinct classes is cleaner in that each class has only one purpose.
However, you end up with a dozen or so classes.

Traits can help eliminate a lot of the duplication, but they can only
capture a small portion of the behavior of the host class without
endangering the unification of responsibility that is one of the key
aspects of OO.

For a simpler example, again in the IO domain, consider various flavors
of buffering (none, char, line, block) and the management of
interprocess or inter-CPU communication with variations such as deferred
write, write through, etc. Decomposing all of the variations produces a
tedious header in conflict with Occam.

Partly this is a design style issue. And partly it is a rigor issue.
Since there is no rational basis for excluding sibling ctors in init
lists there should not be a rule against it. Unnecessary rules are like
unnecessary laws -- they detract from the consistency and cohesiveness,
and thus the worth, of the overall language/legal system.

/tj3

David Abrahams

unread,
Mar 24, 2005, 8:05:18 PM3/24/05
to
John Potter <jpo...@lhup.edu> writes:

> Please show us an example of a function which modifies its reference
> parameter where it would be good to allow temporaries.

Please see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html.
For example, you might search for "allow string I/O to work with
rvalue streams"

On the other hand, those who claim rvalues should just bind to
non-const references willy-nilly have a view that's too simplistic.
If that were the case there would be no way to distinguish rvalues
from lvalues, without which no reasonable move semantics would be
possible.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

David Abrahams

unread,
Mar 25, 2005, 5:57:52 AM3/25/05
to
bran...@cix.co.uk (Dave Harris) writes:

>> Note that if I had my way I'd rather get rid of automatic
>> conversions, but somehow I don't think it's going to happen...
>
> That's a bigger change than I advocated. I think it's enough to suppress
> implicit conversions when the target is a non-const reference. I don't
> think this would break any existing code.

Enabling binding non-const references to temporaries would break any
code that uses a popular technique for implementing move semantics.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Seungbeom Kim

unread,
Mar 25, 2005, 6:06:05 AM3/25/05
to
Trevor L. Jackson, III wrote:
>
> Separate topic: proprocessor symbols can be turned off via #undef while
> language declarations cannot. So the statement that preprocessor
> directive do not respect scope is incorrect. Some do and some do not.
> It depends upon the manning in which the symbols are used.

From the definition of scope that I know, if something respects scope,
- it cannot be referred to from outside its scope, and
- something with the same name in an inner scope supersedes one in an
outer scope.

Preprocessor symbols do not satisfy these properties.

#define max 10

void foo()
{
int max; // Oops!!
}

If the preprocessor symbol max respected scope, it should not have
affected the variable max in the inner scope of foo, but it does. This is
the most annoying thing in using preprocessor symbols.

Manually undefining a symbol has nothing to do with respecting scope,
because you don't have to undefine something in order to be able to use it
in a new scope. Having to write

void foo()
{
#undef max
int max;
}

because there might be something outside with the same name, is just
silly, and we're back in the era where we had no local variables and all
names in a program had to be unique.

> OTOH, language declarations _only_ repect scope, and there are times
> that it is not convenient or even possible to establish a scope boundary
> to terminate a language declaration.
>
> When I can untypedef a symbol, or unint a variable name, I will believe
> that language declarations are universally superior to preprocessor symbols.

Can you give an example where you'd be unable to use the usual scoping
mechanism and have to be able to manually undeclare a symbol?

--
Seungbeom Kim

Gerhard Menzl

unread,
Mar 25, 2005, 6:03:09 AM3/25/05
to
Trevor L. Jackson, III wrote:

> Separate topic: proprocessor symbols can be turned off via #undef
> while language declarations cannot. So the statement that
> preprocessor directive do not respect scope is incorrect. Some do and
> some do not. It depends upon the manning in which the symbols are
> used.

When it is said that the preprocessor does not respect scope, the term
is normally used in the sense of "declarative scope". Now you can insist
on calling the program text between a #define and its corresponding
#undef a scope and point to the heading of 16.3.5 which reads "Scope of
macro definition", but these preprocessor "scopes" are completely
orthogonal to and independent of declarative scopes as seen by the
compiler. Different terminology, same problem: the preprocessor stomps
over your source code like a herd of buffaloes. #undef is a cure that is
hardly better than the disease.

> OTOH, language declarations _only_ repect scope, and there are times
> that it is not convenient or even possible to establish a scope
> boundary to terminate a language declaration.
>
> When I can untypedef a symbol, or unint a variable name, I will
> believe that language declarations are universally superior to
> preprocessor symbols.

Until you come up with a compelling example proving the contrary, I
would boldly claim that whenever you feel the need to do such a thing,
you have got a big design problem. Proper use of the declarative scopes
defined by namespaces and classes should eliminate any need to undeclare
prematurely.


--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Gerhard Menzl

unread,
Mar 25, 2005, 6:02:27 AM3/25/05
to
Trevor L. Jackson, III wrote:

>>>First, there is no need to replace #define symbols. The most that
>>>would be useful would be to warn when a symbol is defined in lower or
>>>mixed case.
>>
>>
>>Just as there is no need for a language beyond C, which is
>>Turing-complete, after all. But there is - at least - one very good
>>reason for replacing preprocessor constants with something that is
>>part of the language rather than a directive for a primitive text
>>conversion utility: const variables respect scope, preprocessor
>>constants don't.
>
>
> I suspect you need to choose your verb more carefully. You said
> replace, which implies the addition of a new facility and the removal
> of the existing facility. That's probably a mistake.

Er, if you care to review this little sub-thread of ours (see triple
quote section above), you will find that it was *you* who came up with
the term "replace". I took it to mean "replace in common use", not
"replace in the language definition", and decided to employ your term in
order to be understood more easily. Why do you think you need to point
out a "mistake" to me which you have made yourself?


--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Francis Glassborow

unread,
Mar 25, 2005, 6:52:49 AM3/25/05
to
In article <PpGdnd7iCKX...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>Gerhard Menzl wrote:
>
>> Trevor L. Jackson, III wrote:
>>
>>
>>>First, there is no need to replace #define symbols. The most that
>>>would be useful would be to warn when a symbol is defined in lower or
>>>mixed case.
>>
>>
>> Just as there is no need for a language beyond C, which is
>> Turing-complete, after all. But there is - at least - one very good
>> reason for replacing preprocessor constants with something that is part
>> of the language rather than a directive for a primitive text conversion
>> utility: const variables respect scope, preprocessor constants don't.
>
>I suspect you need to choose your verb more carefully. You said
>replace, which implies the addition of a new facility and the removal of
>the existing facility. That's probably a mistake.

I think his choice of verb is perfectly suitable. const qualified
globals can be used to replace #define values in C++ code. The mechanism
does not replace the pre-processor one, but the mechanism allows the
programmer to replace use of the pre-processor one. I think it needs an
aggressive misreading of the quoted text.

>
>The addition of a new facility is perfectly reasonable, so long as it
>does not trigger silliness like the change in linkage given to const
>objects.

How is that? C++ invented 'const' it was then adopted by C and the
linkage altered. If you want to complain this is the wrong newsgroup,
try comp.std.c


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Mar 25, 2005, 7:17:35 AM3/25/05
to
In article <P46dnSZslL5...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>A clarification is in order. It may or may not be acceptable to have a
>ctor appear, bare, in it's own or a sibling's init list. The lack of
>ctor return values and the fact that init lists are just expressions
>discourages the practice as much as anything else. However, it is
>certainly possible to put a call to a constructor in a member function,
>and that member function can be invoked in that or another ctor's init
>list. If the inner ctor is a placement new usage then you get the
>effect of sibling ctors indirectly.
>
>Is it your position that the above-described usage violates the standard?

If I correctly understand what you are proposing, yes.

Please provide a class definition/implementation that illustrates what
you are describing.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Trevor L. Jackson, III

unread,
Mar 26, 2005, 4:29:29 AM3/26/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>>>First, there is no need to replace #define symbols. The most that
>>>>would be useful would be to warn when a symbol is defined in lower or
>>>>mixed case.
>>>
>>>
>>>Just as there is no need for a language beyond C, which is
>>>Turing-complete, after all. But there is - at least - one very good
>>>reason for replacing preprocessor constants with something that is
>>>part of the language rather than a directive for a primitive text
>>>conversion utility: const variables respect scope, preprocessor
>>>constants don't.
>>
>>
>>I suspect you need to choose your verb more carefully. You said
>>replace, which implies the addition of a new facility and the removal
>>of the existing facility. That's probably a mistake.
>
>
> Er, if you care to review this little sub-thread of ours (see triple
> quote section above), you will find that it was *you* who came up with
> the term "replace".

Actually not. Please see below.

> I took it to mean "replace in common use", not
> "replace in the language definition", and decided to employ your term in
> order to be understood more easily.

First, the usage interpretation of replace may in fact be the actual
meaning of the OP. And that could be considered a reasonable
suggestion. But I did not interpret it that way due to the context
wherein significant (and damaging) changes were made to the language
specifically for the purpose of achiving the usage replacement, with
implication that once manifest constants could be handled by the
language itself the need for the preprocessor would be reduced and could
be eliminated. I.e., usage change would be driven or forced by language
change.

> Why do you think you need to point
> out a "mistake" to me which you have made yourself?

I thought I needed to point out the consequences of the change in which
light the change is a mistake. However, while you are mistaken about
the fact that I introduced the term replace (see below for original
attributions that you deleted), I was mistaken about the suggestion that
it was you who introduced the term. Neither of us did. Seungbeom Kim
did. I used "you" carelessly, and thus implicitly made unjustified
criticism of your statements, which criticism I hereby retract.

Now if you care to respond to my comments regarding your point about
scope limits I would be interested to hear your reaction.

=== Earlier attributions inserted ===
Seungbeom Kim wrote:

>> Trevor L. Jackson, III wrote:

>>>>3.) Changing the writability of a variable alters the default
linkage of
>>>>the object. This sounds like it was _designed_ to trip up programmers.
>>>> It *cannot* be justified by any amount of rationalization because
>>>>having a keyword silently change the default for an unrelated property
>>>>is *never* a good idea.
>>>>
>>>>Adding or removing constness should not affect any other property
of the
>>>>affected entity. Specifically, it should be possibly to remove all
>>>>const qualifiers from a const-correct program and have a correct
program
>>>>with the same semantics. That is not currently possible.


>
>>
>>
>> You have a point here, and orthogonality is a good idea in general, but
>> this is a complicated issue. Const was designed to replace #define, and
>> therefore it was necessary to treat const as a constant expression.

>It is _not_ hard to achieve. It is hard to achieve in combination
> with the special anti-#define agenda item.

>>
>> Can you suggest another good way of replacing #define'd symbols?

=== end earler attributions ===

/tj3

Trevor L. Jackson, III

unread,
Mar 26, 2005, 4:32:46 AM3/26/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>Separate topic: proprocessor symbols can be turned off via #undef
>>while language declarations cannot. So the statement that
>>preprocessor directive do not respect scope is incorrect. Some do and
>>some do not. It depends upon the manning in which the symbols are
>>used.
>
>
> When it is said that the preprocessor does not respect scope, the term
> is normally used in the sense of "declarative scope". Now you can insist
> on calling the program text between a #define and its corresponding
> #undef a scope and point to the heading of 16.3.5 which reads "Scope of
> macro definition", but these preprocessor "scopes" are completely
> orthogonal to and independent of declarative scopes as seen by the
> compiler. Different terminology, same problem: the preprocessor stomps
> over your source code like a herd of buffaloes.

It may have that effect upon your source code, but it tends to improve
mine. I suspect it depends upon the style and skill with which it is used.

IMHO the preprocessor is like paint in that it covers the plaster and
cracks betweent he drywall that bounds a room in the same sense that
curly braces bound a declarative scope.

Note in passing the suggestion that #scope be added to the preprocessor
as an explicit management tool.

> #undef is a cure that is hardly better than the disease.

I disagree. Further discussion appears to be fruitless because you
appear to have already made up your mind.

>
>
>>OTOH, language declarations _only_ repect scope, and there are times
>>that it is not convenient or even possible to establish a scope
>>boundary to terminate a language declaration.
>>
>>When I can untypedef a symbol, or unint a variable name, I will
>>believe that language declarations are universally superior to
>>preprocessor symbols.
>
>
> Until you come up with a compelling example proving the contrary, I
> would boldly claim that whenever you feel the need to do such a thing,
> you have got a big design problem.

That can be said about any suggestion that the language has limits. So
it doesn't mean much in any specific case. In this case it is flat our
wrong.

For example, it is common to compose complex type expressions using
intermediate typedefs. Yet the convenience and clarity of temporary
type declarations cannot be used to create a file-scope definition
without also polluting the scope with what should be temporaqry type
definitions.

That is not a big design problem. It is simply the nature of scoped
symbols that lack explicit scope management. Claiming that all such
limitations are actually the fault of the design is wrong and
demonstrates a lack of comprehension of the issue.

> Proper use of the declarative scopes
> defined by namespaces and classes should eliminate any need to undeclare
> prematurely.

Care to demonstrate how "proper use" would permit the use of temporary
types to define a non-temporary type? I'll go so far as to suggest that
you cannot do so. The best you can do is to put the temporary types
into a tmp scope such as a namespace or a struct to hide them, but you
will not be able to eliminate the symbol table pollution entirely unless
of course you can eliminate the "big design problem" of the language
rather than the code.

/tj3

Trevor L. Jackson, III

unread,
Mar 26, 2005, 4:34:34 AM3/26/05
to
Seungbeom Kim wrote:

> Trevor L. Jackson, III wrote:
>
>>Separate topic: proprocessor symbols can be turned off via #undef while
>>language declarations cannot. So the statement that preprocessor
>>directive do not respect scope is incorrect. Some do and some do not.
>>It depends upon the manning in which the symbols are used.
>
>
> From the definition of scope that I know, if something respects scope,
> - it cannot be referred to from outside its scope, and
> - something with the same name in an inner scope supersedes one in an
> outer scope.
>
> Preprocessor symbols do not satisfy these properties.

If you definition of scope is implicitly restricte to declarative scopes
delimited by curly braces then you are correct. But that is not
necessarily the only contexts available. The scope of a symbol is the
set of contexts in which the meaning of a symbol is available.

So:

#define SYMBOL /* whatever */

/* use symbol */

#undef SYMBOL

.... defines a scope delimited by the definition and the undefinition.

>
> #define max 10
>
> void foo()
> {
> int max; // Oops!!
> }
>
> If the preprocessor symbol max respected scope, it should not have
> affected the variable max in the inner scope of foo, but it does. This is
> the most annoying thing in using preprocessor symbols.

Yes. Because people are incorrectly taught that declarative scope is
the only scope or the only true scope.

>
> Manually undefining a symbol has nothing to do with respecting scope,
> because you don't have to undefine something in order to be able to use it
> in a new scope. Having to write
>
> void foo()
> {
> #undef max
> int max;
> }
>
> because there might be something outside with the same name, is just
> silly, and we're back in the era where we had no local variables and all
> names in a program had to be unique.
>
>
>>OTOH, language declarations _only_ repect scope, and there are times
>>that it is not convenient or even possible to establish a scope boundary
>>to terminate a language declaration.
>>
>>When I can untypedef a symbol, or unint a variable name, I will believe
>>that language declarations are universally superior to preprocessor symbols.
>
>
> Can you give an example where you'd be unable to use the usual scoping
> mechanism and have to be able to manually undeclare a symbol?
>

Here is one such:

{
typedef template_def_60_chars_long A_t;
typedef template_def_70_chars_long B_t;
typedef template_def_80_chars_long C_t;

typedef A_t< B_t, C_t> my_t;
}

extern my_t const my_variable[]; // oops.

.... compared with ...

#define A_T template_def_60_chars_long
#define B_T template_def_70_chars_long
#define C_T template_def_80_chars_long

typedef A_T< B_T, C_T > my_t;

#undef A_T
#undef B_T
#undef C_T

extern my_t const my_variable[]; // works. no pollution.

The problem is that declarative scopes only nest, they cannot intersect
or overlap. Namespaces are more flexible in that they can be used
intermittently (essentially the ability to reopen a previously named
scope), but they cannot be flushed.

/tj3

Trevor L. Jackson, III

unread,
Mar 26, 2005, 4:36:39 AM3/26/05
to
Francis Glassborow wrote:

> In article <PpGdnd7iCKX...@comcast.com>, "Trevor L. Jackson,
> III" <tl...@comcast.net> writes
>
>>Gerhard Menzl wrote:
>>
>>
>>>Trevor L. Jackson, III wrote:
>>>
>>>
>>>
>>>>First, there is no need to replace #define symbols. The most that
>>>>would be useful would be to warn when a symbol is defined in lower or
>>>>mixed case.
>>>
>>>
>>>Just as there is no need for a language beyond C, which is
>>>Turing-complete, after all. But there is - at least - one very good
>>>reason for replacing preprocessor constants with something that is part
>>>of the language rather than a directive for a primitive text conversion
>>>utility: const variables respect scope, preprocessor constants don't.
>>
>>I suspect you need to choose your verb more carefully. You said
>>replace, which implies the addition of a new facility and the removal of
>>the existing facility. That's probably a mistake.
>
>
> I think his choice of verb is perfectly suitable. const qualified
> globals can be used to replace #define values in C++ code. The mechanism
> does not replace the pre-processor one, but the mechanism allows the
> programmer to replace use of the pre-processor one. I think it needs an
> aggressive misreading of the quoted text.

You may be right. See nearby posts containing discussion of usage
replacement as opposed to language replacement.

Usage replacement is desirable given the assumption of no undesirable
side effects. Language replacement as a wayt o force usage replacement
is anathema.

>
>
>>The addition of a new facility is perfectly reasonable, so long as it
>>does not trigger silliness like the change in linkage given to const
>>objects.
>
>
> How is that? C++ invented 'const' it was then adopted by C and the
> linkage altered. If you want to complain this is the wrong newsgroup,
> try comp.std.c

I think not. If this is where the problem started than this is where
the problem should be fixed. The addition of const to a declatation or
definition should, IMHO, not affect linkage. Why is that a C issue
rather than a C++ issue?

/tj3

Trevor L. Jackson, III

unread,
Mar 26, 2005, 4:39:18 AM3/26/05
to
Francis Glassborow wrote:

> In article <P46dnSZslL5...@comcast.com>, "Trevor L. Jackson,
> III" <tl...@comcast.net> writes
>
>>A clarification is in order. It may or may not be acceptable to have a
>>ctor appear, bare, in it's own or a sibling's init list. The lack of
>>ctor return values and the fact that init lists are just expressions
>>discourages the practice as much as anything else. However, it is
>>certainly possible to put a call to a constructor in a member function,
>>and that member function can be invoked in that or another ctor's init
>>list. If the inner ctor is a placement new usage then you get the
>>effect of sibling ctors indirectly.
>>
>>Is it your position that the above-described usage violates the standard?
>
>
> If I correctly understand what you are proposing, yes.
>
> Please provide a class definition/implementation that illustrates what
> you are describing.

OK this is contrived in the interest of brevity:

/////////// begine example /////////////
class Bad {
double const pi_;
bool have_;
int data_;
void set_pi_()
{
/* bybass const and assign to pi (very bad idea) */
}
public:
Bad()
: have_( false )
{ set_pi_(); }
Bad( int data )
: have_( true )
, data_( data )
{ set_pi_(); }
};

// Assumptions:
// 1) we need to init pi_ in one and only one place.
// 2) we need to init pi_ in a ctor init list
// in order to not violate const correctness.
// 3) mutable is _not_ acceptable because pi_ is not
// in fact modifiable within the life of the object.
//
class Good {
double const pi_;
bool have_;
int data_;
public:
Good()
: have_( false )
, pi_( acos(-1) )
{}
Good( int data )
: have_( new(this) Good(), true )
, data_( data )
{}
};

// Assumption:
// we can invoke a sibling ctor, but its definition must preceed
// the init list in which it is used
//
class Gooder {
double const pi_;
bool have_;
int data_;
Gooder( bool have )
: pi_( acos(-1) )
, have_( have )
{}
public:
Gooder()
: Gooder( false )
{}
Gooder( int data )
: Gooder( true )
, data_( data )
,
};
//////////// end example ///////////////

Francis Glassborow

unread,
Mar 26, 2005, 12:43:08 PM3/26/05
to
In article <xvmdndG6Dbb...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>> How is that? C++ invented 'const' it was then adopted by C and the
>> linkage altered. If you want to complain this is the wrong newsgroup,
>> try comp.std.c
>
>I think not. If this is where the problem started than this is where
>the problem should be fixed. The addition of const to a declatation or
>definition should, IMHO, not affect linkage. Why is that a C issue
>rather than a C++ issue?

Why do you suggest that it should not affect linkage. const qualified
objects will have linkage, the only question is what that linkage should
be. I am not alone in believing that C's making the default linkage for
filescope declarations extern was a design error (albeit a small one).

When C++ was initially being designed a code translator was used to
convert C++ source to C. And there was no concept of const in C at that
time. As the C++ version of const (the original version of const which C
borrowed and changed) was vulnerable to redefinition errors if it was
not restricted to filescope, it seems entirely logical that the keyword
incorporated 'static' (i.e. non-extern) linkage rather than require
programmers to add static to many uses they made of const (and have to
consciously determine when they did or did not. The default linkage of
const seems correct to me, and the latter addition of allowing that
default to be overruled also seems sensible.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Mar 26, 2005, 12:40:50 PM3/26/05
to
In article <ZbGdndDxOaJ...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>OK this is contrived in the interest of brevity:

OK, but it shows exactly the kinds of misconceptions that I suspected.


>
>/////////// begine example /////////////
> class Bad {
> double const pi_;
> bool have_;
> int data_;
> void set_pi_()
> {
> /* bybass const and assign to pi (very bad idea) */

That results in undefined behaviour and so is not an acceptable solution
in any code shop that knows what it is doing.

I think I would take out and shoot a programmer who wanted to use
placement new that way.

> , data_( data )
> {}
> };
>
> // Assumption:
> // we can invoke a sibling ctor, but its definition must preceed
> // the init list in which it is used
> //
> class Gooder {
> double const pi_;
> bool have_;
> int data_;
> Gooder( bool have )
>: pi_( acos(-1) )
> , have_( have )
> {}
> public:
> Gooder()
>: Gooder( false )
> {}
> Gooder( int data )
>: Gooder( true )

And that will not currently compile and that is the issue addressed by
the joint proposal from me and Herb Sutter for the next version of C++

> , data_( data )
> ,
> };
>//////////// end example ///////////////

Of your three proposed solutions, only the second is well-formed code
free from undefined behaviour. That solution relies on a fragile
mechanism that works in this instance but is not universal and is
problematic in the presence of exceptions. Your class has a trivial dtor
so the problem will not arise but for any class with a non-trivial dtor
your mechanism is unsafe.

However your example is an example of poor design. If something has a
single immutable value for all instances of a class it should be a
static member of the class.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Mar 26, 2005, 12:44:11 PM3/26/05
to
In article <w-idnWWAorf...@comcast.com>, "Trevor L. Jackson,
III" <tl...@comcast.net> writes

>Here is one such:
>
> {
> typedef template_def_60_chars_long A_t;
> typedef template_def_70_chars_long B_t;
> typedef template_def_80_chars_long C_t;
>
> typedef A_t< B_t, C_t> my_t;
> }
>
> extern my_t const my_variable[]; // oops.

And what is wrong with:

namespace ex {


typedef template_def_60_chars_long A_t;
typedef template_def_70_chars_long B_t;
typedef template_def_80_chars_long C_t;

typedef A_t< B_t, C_t> my_t;
}

using ex::my_t;

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Mar 26, 2005, 5:31:32 PM3/26/05
to
this country. And you should drop it in their lap.
This government has failed the Negro. This so-called democracy has
failed the Negro. And all these white liberals have definitely failed
the Negro.

So, where do we go from here? First, we need some friends. We need some
new allies. The entire civil-rights struggle needs a new interpretation,
a broader interpretation. We need to look at this civil-rights thing
from another angle -- from the inside as well as from the outside. To
those of us whose philosophy is black nationalism, the only way you can
get involved in the civil-rights struggle is give it a new
interpretation. That old interpretation excluded us. It kept us out. So,
we're giving a new interpretation to the civil-rights struggle, an
interpretation that will enable us to come into it, take part in it. And
these handkerchief-heads who have been dillydallying and pussy footing
and compromising -- we don't intend to let them pussyfoot and dillydally
and compromise any longer.

How can you thank a man for giving you what's already yours? How then
can you thank him for giving you only part of what's already yours? You
haven't even made progress, if what's being given to you, you should
have had already. That's not progress. And I love my Brother Lomax, the
way he pointed out we're right back where we were in 1954. We'r


Francis Glassborow

unread,
Mar 26, 2005, 6:24:42 PM3/26/05
to
to pass civil-rights bills for
Africans. An African can go anywhere he wants right now. All you've got
to do is tie your head up. That's right, go anywhere you want. Just stop
being a Negro. Change your name to Hoogagagooba. That'll show you how
silly the white man is. You're dealing with a silly man. A friend of
mine who's very dark put a turban on his head and went into a restaurant
in Atlanta before they called themselves desegregated. He went into a
white restaurant, he sat down, they served him, and he said, "What would
happen if a Negro came in here? And there he's sitting, black as night,
but because he had his head wrapped up the waitress looked back at him
and says, "Why, there wouldn't no nigger dare come in here."

So, you're dealing with a man whose bias and prejudice are making him
lose his mind, his intelligence, every day. He's frightened. He looks
around and sees what's taking place on this earth, and he sees that the
pendulum of time is swinging in your direction. The dark people are
waking up. They're losing their fear of the white man. No place where
he's fighting right now is he winning. Eve


Francis Glassborow

unread,
Mar 26, 2005, 6:24:38 PM3/26/05
to
Revolution is based on land. Land is the
basis of all independence. Land is the basis of freedom, justice, and
equality.

The white man knows what a revolution is. He knows that the black
revolution is world-wide in scope and in nature. The black revolution is
sweeping Asia, sweeping Africa, is rearing its head in Latin America.
The Cuban Revolution -- that's a revolution. They overturned the system.
Revolution is in Asia. Revolution is in Africa. And the white man is
screaming because he sees revolution in Latin America. How do you think
he'll react to you when you learn what a real revolution is? You don't
know what a revolution is. If you did, you wouldn't use that word.

A revolution is bloody. Revolution is hostile. Revolution knows no
compromise. Revolution overturns and destroys everything that gets in
its way. And you, sitting around here like a knot on the wall, saying,
"I'm going to love these folks no matter how much they hate me." No, you
need a revolution. Whoever heard of a revolution where t


Trevor L. Jackson, III

unread,
Mar 27, 2005, 5:33:47 AM3/27/05
to
Francis Glassborow wrote:

> In article <xvmdndG6Dbb...@comcast.com>, "Trevor L. Jackson,
> III" <tl...@comcast.net> writes
>
>>>How is that? C++ invented 'const' it was then adopted by C and the
>>>linkage altered. If you want to complain this is the wrong newsgroup,
>>>try comp.std.c
>>
>>I think not. If this is where the problem started than this is where
>>the problem should be fixed. The addition of const to a declatation or
>>definition should, IMHO, not affect linkage. Why is that a C issue
>>rather than a C++ issue?
>
>
> Why do you suggest that it should not affect linkage. const qualified
> objects will have linkage, the only question is what that linkage should
> be.

I agree with your overall statement of the issue. Now let's make it a
bit more specific. Given three possible linkage directives
corresponding to extern, static, and empty, we only care about the empty
case where default linkage is pertinent.

The issue is consistency. Should all objects with empty linkage
specifications have the same default linkage? IMHO they should. If
they do not then there is no limit on the number of things that might
alter the general rule of empty means extern.

If const objects have a default linkage that does not match the general
default linkage, should ints and floats be different? Better yet,
should character string literals be different so that compilers might
coalesce multiple copies of the same strings?

Should the spelling of the object name affect the default linkage?
After all C++ might want to recruit FORTRAN programmers and they are
used to implicit integer I-N so implicit static K might make sense to them.

Should names in all caps affect the default linkage? After all it might
be a good idea to encourage people to adopt const objects in place of
preprocessor symbols and all caps is one way to offer an encouraging
connotation that the target programmers will be more comfortable with.

IMHO all of the above concepts suck. Partly because they are not worth
much (although the exercise of coming up with arguments in favor of
diddling the default linkage was a bit scary -- it was too easy to find
arguments in favor of making things more complicated). But mostly the
above suggestions suck because having different sets of default linkages
sucks.

IMHO const-correctness is quite valuable. I don't want people avoiding
const declarations because it gives the symbols the "wrong" linkage
ITHO. I fear they will avoid the const rather than learn that they have
to use an explicit linkage directive to get what they want when they use
const. It will be easier for them to avoid const completely than to
remember when they have to compensate for the unfortunate side effects
of const'ing a declaration.

> I am not alone in believing that C's making the default linkage for
> filescope declarations extern was a design error (albeit a small one).

I happen to agree and would be mildly encouraged if that was changed in
C++. However, I doubt that could ever come to pass because it would
widen the rifts between C++ and C and break an lot of existing code.

>
> When C++ was initially being designed a code translator was used to
> convert C++ source to C. And there was no concept of const in C at that
> time. As the C++ version of const (the original version of const which C
> borrowed and changed) was vulnerable to redefinition errors if it was
> not restricted to filescope, it seems entirely logical that the keyword
> incorporated 'static' (i.e. non-extern) linkage rather than require
> programmers to add static to many uses they made of const (and have to
> consciously determine when they did or did not. The default linkage of
> const seems correct to me, and the latter addition of allowing that
> default to be overruled also seems sensible.

It might appear correct, by which I think you mean "natural", to you due
to long familiarity and/or a deeper understanding of the history of the
"feature", or even due to a deeper understanding of the rationale for
violating the default linkage that affects all other objects. But none
of those generalize to the larger population of programmers.

This issue needs some more KISSing in order to promote simplicity via
independence and orthogonality.

/tj3

Trevor L. Jackson, III

unread,
Mar 27, 2005, 5:34:23 AM3/27/05
to
Francis Glassborow wrote:

> In article <w-idnWWAorf...@comcast.com>, "Trevor L. Jackson,
> III" <tl...@comcast.net> writes
>
>>Here is one such:
>>
>> {
>> typedef template_def_60_chars_long A_t;
>> typedef template_def_70_chars_long B_t;
>> typedef template_def_80_chars_long C_t;
>>
>> typedef A_t< B_t, C_t> my_t;
>> }
>>
>> extern my_t const my_variable[]; // oops.
>
>
> And what is wrong with:
>
> namespace ex {
> typedef template_def_60_chars_long A_t;
> typedef template_def_70_chars_long B_t;
> typedef template_def_80_chars_long C_t;
>
> typedef A_t< B_t, C_t> my_t;
> }
> using ex::my_t;

There are too many things that are not affected by using. In particular
enumerations are not well treated thereby.

Also it is hard to generate independent namespaces for each such
temporary scope. Putting unnamed namespaces in header files tends to
cause problems.

/tj3

Peter C. Chapin

unread,
Mar 27, 2005, 9:35:12 AM3/27/05
to
M Jared Finder <ja...@hpalace.com> wrote in
news:42423...@x-privat.org:

> I was following you up until the last sentence. First, how is goto
> "unrestrained"? Second, how does this unrestrained-ness make tool
> construction hard? I don't see how the program flow introduced by
> goto is any more complicated than the program flow introduced by
> while.

The goto allows you to create programs with irreducible flow graphs
(essentially... non-nested control flow structures). For example:

if (x == y) goto L1;
L2: f1();
L1: f2();
if (a == b) goto L2;

Off hand I don't know of any analysis applications that can't be done
due to having this sort of flexibility in the language, but it wouldn't
surprise me if there were some. I do know that data flow analysis can be
done more efficiently if the program has a reducible flow graph but it I
believe it can still be done in general regardless. Nevertheless this by
itself might be significant since many software analysis methods are
built on data flow techniques.

Peter

Motti Lanzkron

unread,
Mar 27, 2005, 9:34:25 AM3/27/05
to
Dave Harris wrote:
>jpo...@lhup.edu (John Potter) wrote (abridged):

>> Please show us an example of a function which modifies its reference
>> parameter where it would be good to allow temporaries.

One way to get this behaviour in the current C++ is to add an "lvalue
cast".

template <typename T>
T& lvalue_cast(const T& t)
{
return const_cast<T&>(t);
}

It's clunky to use and might explode in your face if the reference is
stored (or the value is passed to a constructor) but if these caveats
are acceptable it's rather handy as well as being semi-expresive.

>A classic is:
>
> v.swap( vector<int>() );

v.swap( lvalue_cast(vector<int>()) );

void foo(std::string& s);
...
foo(lvalue_cast<std::string>("plonk"));

In fact when moving from VS6 to 7 we ran across a lot of COM methods
that expected pointers to variants and this function came in handy:

CComVariant& TempVariant(const CComVaraint& v = CComVariant())
{
return const_cast<CComVaraint&>(v); // (*)
}

so you could write:
foo(&TempVariant(42)); instead of the illegal foo(&CComVariant(42));

(*) Side note: does anyone else think that const_cast should assume
the non-const return type of the parameter if the template parameter
is excluded?

Currently it's as if const_cast is defined like this:
template <typename T, typename U>
T const_cast(const U u) { return (T)u;}

Instead of like this:
template <typename T> T& const_cast(const T& t) { return (T&)t;}
template <typename T> T* const_cast(const T* t) { return (T*)t;}

Seungbeom Kim

unread,
Mar 28, 2005, 6:59:05 AM3/28/05
to
Francis Glassborow wrote:

> When C++ was initially being designed a code translator was used to
> convert C++ source to C. And there was no concept of const in C at that
> time. As the C++ version of const (the original version of const which C
> borrowed and changed) was vulnerable to redefinition errors if it was
> not restricted to filescope, it seems entirely logical that the keyword
> incorporated 'static' (i.e. non-extern) linkage rather than require
> programmers to add static to many uses they made of const (and have to
> consciously determine when they did or did not. The default linkage of
> const seems correct to me, and the latter addition of allowing that
> default to be overruled also seems sensible.

While this might make sense for those who know the history of C++, it's
still an "implementation detail" and C++ is rarely "preprocessed" into C
these days, anyway.

It may be easier for a new C++ programmer to program with such different
default values at first, but as soon as he/she encounters the concept of
constness and linkage, he/she is likely to stumble over the fact that
there was actually a special rule, an exception, that adding const had
changed the default linkage. On the other hand, it won't be as hard to
teach a new programmer to write "static const" whenever he/she needs a
named constant, and he/she will later understand what it has meant.

--
Seungbeom Kim

Francis Glassborow

unread,
Mar 28, 2005, 12:33:18 PM3/28/05
to
In article <d27vdn$kfn$1...@news.Stanford.EDU>, Seungbeom Kim
<musi...@bawi.org> writes

>It may be easier for a new C++ programmer to program with such different
>default values at first, but as soon as he/she encounters the concept of
>constness and linkage, he/she is likely to stumble over the fact that
>there was actually a special rule, an exception, that adding const had
>changed the default linkage. On the other hand, it won't be as hard to
>teach a new programmer to write "static const" whenever he/she needs a
>named constant, and he/she will later understand what it has meant.

I have never had a novice confused by the use of const. But perhaps it
is because I rarely ever use it in a 'global' context. In fact what they
find far more confusing is the need to add 'extern' when used where
extern linkage is needed because they find it hard to see why we would
ever want to do that. How often do you want a global constant to
actually have an identity?

Well you might for some forms of meta-programming or template usage but
that is hardly novice stuff.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

ka...@gabi-soft.fr

unread,
Mar 29, 2005, 4:36:35 AM3/29/05
to
Francis Glassborow wrote:
> In article <xvmdndG6Dbb...@comcast.com>, "Trevor
> L. Jackson, III" <tl...@comcast.net> writes

> >> How is that? C++ invented 'const' it was then adopted by C
> >> and the linkage altered. If you want to complain this is
> >> the wrong newsgroup, try comp.std.c

> >I think not. If this is where the problem started than this
> >is where the problem should be fixed. The addition of const
> >to a declatation or definition should, IMHO, not affect
> >linkage. Why is that a C issue rather than a C++ issue?

> Why do you suggest that it should not affect linkage.

Because the concepts are orthogonal. Why on earth should it
affect linkage?

> const qualified objects will have linkage, the only question
> is what that linkage should be.

All objects have linkage (supposing for the moment that we
consider no linkage a type of linkage:-)). The question is why
adding const should change the linkage, and not just the
modifiability. And only for variables at namespace scope, of
course; const has no effect on the linkage of member variables
nor of local variables.

In practice, it's usually a minor point, but it is a lack of
orthogonality, and as such, a source of confusion to beginners.

> I am not alone in believing that C's making the default
> linkage for filescope declarations extern was a design error
> (albeit a small one).

> When C++ was initially being designed a code translator was
> used to convert C++ source to C. And there was no concept of
> const in C at that time. As the C++ version of const (the
> original version of const which C borrowed and changed) was
> vulnerable to redefinition errors if it was not restricted to
> filescope, it seems entirely logical that the keyword
> incorporated 'static' (i.e. non-extern) linkage rather than
> require programmers to add static to many uses they made of
> const (and have to consciously determine when they did or did
> not.

I fail to see the problem. If I don't want linkage, I can
always write :

static double const pi = 3.14159 ;

(I do this anyway. At least my code is consistent -- a variable
at namespace scope which doesn't have linkage is declared
const.)

I understand the arguments in favor of no linkage, but in the
end, it boils down to simply allowing a certain laziness on the
part of the programmer; he doesn't have to write the static. On
the other hand, it can lead to confusion in other contexts: if
the const is introduced via a typedef, for example, and isn't
immediately visible.

It's not the end of the world, but it's one more gotcha to watch
out for.

> The default linkage of const seems correct to me, and the
> latter addition of allowing that default to be overruled also
> seems sensible.

Being able to have const objects with external linkage seems
essential; if the object has a non-trivial constructor, you
probably don't want to construct it in each translation unit in
which the header is included. (But of course, order of
initialization considerations mean that one typically avoids
objects with namespace scope which have non-trivial
constructors.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Nicola Musatti

unread,
Mar 29, 2005, 5:04:44 PM3/29/05
to
Aren't you forgetting 'volatile'?

Cheers,
Nicola Musatti

Nicola Musatti

unread,
Mar 29, 2005, 5:08:45 PM3/29/05
to

Trevor L. Jackson, III wrote:
> Nicola Musatti wrote:
[...]
> > You can't really expect the language to simplify a convoluted
design,
> > can you?. Initialization in a constructor is about dealing with
members
> > one at a time;
>
> Oh really? Why is that? And where is that?

It is directly analogous to how free variables are handled. You cannot
inititialize more than one variable in a single statement, can you?

[I know you can write

A a = b, c = d;

but these are still two separate initializations]

> There is no real advantage
> to mandating that members, by which I assume you improperly means to
> include base classes, be dealt with individually.

Apart from the support to writing correct code that derives from clear
and rigorous semantics.

> In fact theer are
> serious disadvantages to that approach. One is that it often leads
to
> code duplicattion. Another is the temptation to introduce an
artificial
> abstraction in the handling of members only for the purposes of
> initialization.

The new abstraction is not artificial if it serves a purpose, even if
it might not directly model a real world entity.

> > if you need to handle a subset of them together the
> > right tool is a class.
>
> I disagree. Quite strongly. Your statement depends upon the
assumption
> that the various sets of members can be arranged into a sequence of
> proper subsets. That assumption isn't always true. If the members A

> and B ned to be initialized in one instance and the members B and C
> needs to be initializaed in another instance, should I multiply
inherit
> from parents classes AB and BC each of which inherit from virtual
class
> B (which is a wrapper for a built-in type)? I'm not going to do
that,
> nor let any of my coders do that.
>
> What was it you were saying about simplifying a convoluted design?

Thank you for your perfect example of a convoluted design in dire need
of simplification :-) More seriously though, judging from my experience
I would really consider something like your example as an indication
that some refactoring is in order, but I'm prepared to accept that
there may be real cases where this is not possible.

> Recursive placement new based on partial ctors (each of which manages

> only a fraction of the full collection of members) is far superior
> because they all appear together and the design can be clearly
explained
> in one a single place within the code.

I don't find this that superior to a set of base classes whose purpose
is to allow the best factorization of similar sets of interdependent
members. Moreover, if you define these classes' constructors inline,
even the resulting code is not much more complicated than the solution
you envision.

> >>>I'm convinced that forwarding constructors are a
> >>>bad idea and will prove to be more a source of errors than a help.
> >>
> >>Why is calling a sibling contructor a problem where calling a base
> >>class constructor is not?
> >
> > Because the inheritance relationship imposes an ordering that helps
> > keep things clear: you'll never be able to call the derived class
> > constructor first, so you don't have to worry about it. Not so with
> > forwarding constructors; at best you'll have to introduce arbitrary
and
> > hard to understand limitations on their use, at worst every
constructor
> > will have to be coded keeping in mind that it may be called either
> > before or after other constructors.
>
> The ordering you seek should be derived from the ordering of the
> declarations of the constructors. Any other rule leads to the
> possibility of mutual recursion during initialization, and init lists

> are not places I want to see stack checking.

These rules are analogous to those that hold for the construction of
base subobjects, with the disadvantage of relying on code ordering.

> But what is the worst thing that can happen? Someone writes a group
of
> ctors with a circular set of references. How is this badder (a
> technical term) than permitting coders to write functions with a
> circular set of references? Ctor init lists and calls to sibling
ctors
> can be just as conditional as mutual recursion or self recusrsion in
> normal functions.

It is worse because it is a gratuitous addition of a way to hurt
oneself without a significant gain.

> Self-recursion does not appear to be useful for ctors, but even today

> you can put a call to a ctor in its own init list without violating
the
> standard. Why should that change?

[I read your subsequent example]
Yet it's hardly something you might end up doing due to carelessness.
It does take some ingenuity.

> > And what about destruction order, both in normal conditions and
during
> > stack unwinding?
>
> Destruction order is determined by membership declaration order.
> Constructors have no influence upon destruction. So I do not
understand
> the question. Can you amplify it?

You're right. Never mind.

Nicola Musatti

unread,
Mar 29, 2005, 9:05:37 PM3/29/05
to
by loosening from the edges,
then stripping off.
Season generously, rubbing the mixture into the baby?s flesh.
Place 1 quart water in a baking pan, the meat on a wire rack.
Bake uncovered in 250° oven for 1½ hours.
When browned, remove and glaze,
return to oven and bake 20 minutes more to form a glaze.
Cut ribs into individual pieces and serve with extra sauce.

Fresh Sausage

If it becomes necessary to hide the fact that you are eating
human babies, this is the perfect solution.
But if you are still paranoid, you can substitute pork butt.

5 lb. lean chuck roast
3 lb. prime baby butt
2 tablespoons each:
salt
black, white and cayenne peppers
celery salt
garlic powder
parsley flakes
brown sugar
1 teaspoon sage
2 onions
6 cloves garlic
bunch green onions, chopped

Cut the children?s butts and the beef roast into pieces
that will fit in the grinder.
Run the meat through using a 3/16 grinding plate.
Add garlic, onions and seasoning then mix well.
Add just enough water for a smooth consistency, then mix again.
Form the sausage mixture into patties or stuff into natural casings.

Stillborn Stew

By definition, this meat cannot be had altogether fresh,
but have the lifeless unfortunate available immediately after delivery,
or use high quality beef or pork roasts (it is cheaper and better to
cut up a whole roast than to buy stew meat).

1 stillbirth, de-boned and cubed
¼ cup vegetable oil
2 large onions
bell pepper
celery
garlic
½ cup red wine
3 Irish potatoes
2 large carrots


Trevor L. Jackson, III

unread,
Mar 30, 2005, 6:30:29 PM3/30/05
to
Nicola Musatti wrote:

> Trevor L. Jackson, III wrote:
>
>>Nicola Musatti wrote:
>
> [...]
>
>>>You can't really expect the language to simplify a convoluted
>
> design,
>
>>>can you?. Initialization in a constructor is about dealing with
>
> members
>
>>>one at a time;
>>
>>Oh really? Why is that? And where is that?
>
>
> It is directly analogous to how free variables are handled. You cannot
> inititialize more than one variable in a single statement, can you?
>
> [I know you can write
>
> A a = b, c = d;
>
> but these are still two separate initializations]

Well, if you accept a minor quibble the following might qualify:

T a, b = a = complex_expr;

The quibble is that a isn't really being initilialized in the strict
sense of the term. It is being assigned to. However, I cn quibble with
that by suggesting that any reasonable compiler is going to emit code
that will look like initialization of both a and b occurs.

More interestingly:

T a = complex_expr, b = a;

would initialize both variables, but I think its correctness is
uncertain -- it will work on some compilers and fail on others
(standardization of a feature of the language does not change that
possibility, it merely lends weight to one's complaints to the compiler
vendor).

>
>
>>There is no real advantage
>>to mandating that members, by which I assume you improperly means to
>>include base classes, be dealt with individually.
>
>
> Apart from the support to writing correct code that derives from clear
> and rigorous semantics.

Wht is unclear or lacks rigor in the concept of using sibling ctors in
initialization lists?

[snip]


>>Recursive placement new based on partial ctors (each of which manages
>
>
>>only a fraction of the full collection of members) is far superior
>>because they all appear together and the design can be clearly
>
> explained
>
>>in one a single place within the code.
>
>
> I don't find this that superior to a set of base classes whose purpose
> is to allow the best factorization of similar sets of interdependent
> members. Moreover, if you define these classes' constructors inline,
> even the resulting code is not much more complicated than the solution
> you envision.

I like Occam's Razor. YMMV.

>
>
>>>>>I'm convinced that forwarding constructors are a
>>>>>bad idea and will prove to be more a source of errors than a help.
>>>>
>>>>Why is calling a sibling contructor a problem where calling a base
>>>>class constructor is not?
>>>
>>>Because the inheritance relationship imposes an ordering that helps
>>>keep things clear: you'll never be able to call the derived class
>>>constructor first, so you don't have to worry about it. Not so with
>>>forwarding constructors; at best you'll have to introduce arbitrary
>
> and
>
>>>hard to understand limitations on their use, at worst every
>
> constructor
>
>>>will have to be coded keeping in mind that it may be called either
>>>before or after other constructors.
>>
>>The ordering you seek should be derived from the ordering of the
>>declarations of the constructors. Any other rule leads to the
>>possibility of mutual recursion during initialization, and init lists
>
>
>>are not places I want to see stack checking.
>
>
> These rules are analogous to those that hold for the construction of
> base subobjects, with the disadvantage of relying on code ordering.

The only disadvantage I see related to ordering is that using a
forwarding ctor would allow out-of-order intitialization of members.
For example, given base classes B1, B2 and data members M1, M2, M3, any
non-forwarding ctor init list preserves the init order to match the decl
order.

However, with a forwarding ctor that ordering can be compromised. If
ctor() inits B2, M1, and M2 and forwards to ctor( B1_t const&, M3_t
const &) then there is not ordering of actions in ctor()'s init list
that preserves the order of initialization of base classes and members.

it is not clear to me that this is particularly dangerous, but it does
create a trap for the unwary.

>
>
>>But what is the worst thing that can happen? Someone writes a group
>
> of
>
>>ctors with a circular set of references. How is this badder (a
>>technical term) than permitting coders to write functions with a
>>circular set of references? Ctor init lists and calls to sibling
>
> ctors
>
>>can be just as conditional as mutual recursion or self recusrsion in
>>normal functions.
>
>
> It is worse because it is a gratuitous addition of a way to hurt
> oneself without a significant gain.

I believe there is a gain. One might argue that recusrion in general
should be prohibited because in principle any design based upon
recusrion can be changed into one based upon iteration, which generally
makes the code clearer, but often more voluminuous.

/tj3

Nicola Musatti

unread,
Mar 31, 2005, 9:03:50 AM3/31/05
to

Trevor L. Jackson, III wrote:
> Nicola Musatti wrote:
[...]
> > It is directly analogous to how free variables are handled. You
cannot
> > inititialize more than one variable in a single statement, can you?
> >
> > [I know you can write
> >
> > A a = b, c = d;
> >
> > but these are still two separate initializations]
>
> Well, if you accept a minor quibble the following might qualify:
>
> T a, b = a = complex_expr;
>
> The quibble is that a isn't really being initilialized in the strict
> sense of the term. It is being assigned to. However, I cn quibble
with
> that by suggesting that any reasonable compiler is going to emit code

> that will look like initialization of both a and b occurs.

This to me appears to be the same as never using initialization lists
in constructors and put all "initialisation" code in the constructor
bodies, thus solving all your problems in a much simpler way than your
placement new technique.

[...]


> >>There is no real advantage
> >>to mandating that members, by which I assume you improperly means
to
> >>include base classes, be dealt with individually.
> >
> > Apart from the support to writing correct code that derives from
clear
> > and rigorous semantics.
>
> Wht is unclear or lacks rigor in the concept of using sibling ctors
in
> initialization lists?

The need to rely on code placement to enforce order of execution
constraints, or to give them up altogether.

>
> >>Recursive placement new based on partial ctors (each of which
manages
> >>only a fraction of the full collection of members) is far superior
> >>because they all appear together and the design can be clearly
> >>explained in one a single place within the code.
> >
> > I don't find this that superior to a set of base classes whose
purpose
> > is to allow the best factorization of similar sets of
interdependent
> > members. Moreover, if you define these classes' constructors
inline,
> > even the resulting code is not much more complicated than the
solution
> > you envision.
>
> I like Occam's Razor. YMMV.

So do I. Where mileage does vary is in what we consider to be
"purpose".

[...]


> > These rules are analogous to those that hold for the construction
of
> > base subobjects, with the disadvantage of relying on code ordering.
>
> The only disadvantage I see related to ordering is that using a
> forwarding ctor would allow out-of-order intitialization of members.
> For example, given base classes B1, B2 and data members M1, M2, M3,
any
> non-forwarding ctor init list preserves the init order to match the
decl
> order.
>
> However, with a forwarding ctor that ordering can be compromised. If

> ctor() inits B2, M1, and M2 and forwards to ctor( B1_t const&, M3_t
> const &) then there is not ordering of actions in ctor()'s init list
> that preserves the order of initialization of base classes and
members.
>
> it is not clear to me that this is particularly dangerous, but it
does
> create a trap for the unwary.

It's still worse than being free to place your constructors in the
order you prefer.

> >>But what is the worst thing that can happen? Someone writes a
group
> >>of ctors with a circular set of references. How is this badder (a
> >>technical term) than permitting coders to write functions with a
> >>circular set of references? Ctor init lists and calls to sibling
> >>ctors can be just as conditional as mutual recursion or self
> >>recusrsion in normal functions.
> >
> > It is worse because it is a gratuitous addition of a way to hurt
> > oneself without a significant gain.
>
> I believe there is a gain. One might argue that recusrion in general

> should be prohibited because in principle any design based upon
> recusrion can be changed into one based upon iteration, which
generally
> makes the code clearer, but often more voluminuous.

I do not, but you know that. By the way, in my experience designs based
on recursion are often clearer than iterative ones, because they tend
to be more abstract and because function calls hide explicit stack
management. The only case where I find recursion less clear is when it
is used to mimick explicit iteration.

Cheers,
Nicola Musatti

Gerhard Menzl

unread,
Mar 31, 2005, 9:11:34 AM3/31/05
to
Trevor L. Jackson, III wrote:

>>I have a hard time imagining a concrete example for a class where
>>different instances initialize different members. Call me naive, but
>>my classes always have their instances initialize all members. Or are
>>you talking about different subclasses? An example would be most
>>helpful.
>
> It would take several pages in order to provide a concrete example
> that could not be criticized as contrived. But consider an abstract
> example based on the C++ streams library. In a tight memory situation
> one might forgo the variations of (i/o/io)(' '/f/str/string)streams
> and provide a single, unified IO model whose ctors managed the
> appropriate subset of the unified class' functionality. Yes, a
> decomposition into separate distinct classes is cleaner in that each
> class has only one purpose. However, you end up with a dozen or so
> classes.

So? That's what class design is about. Different responsibilities,
different classes. Bundling un- or little related functionality within a
single class and then telling it every time which personality to assume
is the object-oriented variation of what is known as control coupling
(the second worst form of coupling) in structured programming.

What makes you think that control-coupled classes use significantly less
memory, by the way? And even if you decide to use such a shapeshifter
against all reason, you still have to initialize the members you don't
need (by setting pointers to null, for example).

> Partly this is a design style issue. And partly it is a rigor issue.

I think it is all about design. I also think that design without a
certain degree of rigour is bound to fail.

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

Gerhard Menzl

unread,
Mar 31, 2005, 9:10:47 AM3/31/05
to
Trevor L. Jackson, III wrote:

> First, the usage interpretation of replace may in fact be the actual
> meaning of the OP. And that could be considered a reasonable
> suggestion. But I did not interpret it that way due to the context
> wherein significant (and damaging) changes were made to the language
> specifically for the purpose of achiving the usage replacement, with
> implication that once manifest constants could be handled by the
> language itself the need for the preprocessor would be reduced and
> could be eliminated. I.e., usage change would be driven or forced by
> language change.

Can we agree that we don't want to remove #define from the language
definition, and that I think people should be encouraged to reduce its
use to an absolute minimum?

> Now if you care to respond to my comments regarding your point about
> scope limits I would be interested to hear your reaction.

I have responded regarding scope in a different sub-thread and. Which
point apart from this do you want me to respond to? I have lost track
amid those undulating quotes.


--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Trevor L. Jackson, III

unread,
Apr 1, 2005, 2:14:21 AM4/1/05
to
Nicola Musatti wrote:
> Trevor L. Jackson, III wrote:
>
>>Nicola Musatti wrote:
>
> [...]
>
>>>It is directly analogous to how free variables are handled. You
>
> cannot
>
>>>inititialize more than one variable in a single statement, can you?
>>>
>>>[I know you can write
>>>
>>>A a = b, c = d;
>>>
>>>but these are still two separate initializations]
>>
>>Well, if you accept a minor quibble the following might qualify:
>>
>> T a, b = a = complex_expr;
>>
>>The quibble is that a isn't really being initilialized in the strict
>>sense of the term. It is being assigned to. However, I cn quibble
>
> with
>
>>that by suggesting that any reasonable compiler is going to emit code
>
>
>>that will look like initialization of both a and b occurs.
>
>
> This to me appears to be the same as never using initialization lists
> in constructors and put all "initialisation" code in the constructor
> bodies, thus solving all your problems in a much simpler way than your
> placement new technique.

In some cases it is possible to assign each member within the object.
However, while that is OK for built-in types and PODs, it does not work
well for objects. It does not work at all for base classes.

And for all base classes and members it does not provide the automaic
ordering that initialization lists provide.

>
> [...]
>
>>>>There is no real advantage
>>>>to mandating that members, by which I assume you improperly means
>
> to
>
>>>>include base classes, be dealt with individually.
>>>
>>>Apart from the support to writing correct code that derives from
>
> clear
>
>>>and rigorous semantics.
>>
>>Wht is unclear or lacks rigor in the concept of using sibling ctors
>
> in
>
>>initialization lists?
>
>
> The need to rely on code placement to enforce order of execution
> constraints, or to give them up altogether.

By order of execution do you mean order of init?

>
>
>>>>Recursive placement new based on partial ctors (each of which
>
> manages
>
>>>>only a fraction of the full collection of members) is far superior
>>>>because they all appear together and the design can be clearly
>>>>explained in one a single place within the code.
>>>
>>>I don't find this that superior to a set of base classes whose
>
> purpose
>
>>>is to allow the best factorization of similar sets of
>
> interdependent
>
>>>members. Moreover, if you define these classes' constructors
>
> inline,
>
>>>even the resulting code is not much more complicated than the
>
> solution
>
>>>you envision.
>>
>>I like Occam's Razor. YMMV.
>
>
> So do I. Where mileage does vary is in what we consider to be
> "purpose".

If the factorization youi mentioned is a natural one for the object it
should be done without using init as a justification. If the
factorization is only for the purposes of init then it is probably
unnatural for the object and should not be done at all.

>
> [...]
>
>>>These rules are analogous to those that hold for the construction
>
> of
>
>>>base subobjects, with the disadvantage of relying on code ordering.
>>
>>The only disadvantage I see related to ordering is that using a
>>forwarding ctor would allow out-of-order intitialization of members.
>>For example, given base classes B1, B2 and data members M1, M2, M3,
>
> any
>
>>non-forwarding ctor init list preserves the init order to match the
>
> decl
>
>>order.
>>
>>However, with a forwarding ctor that ordering can be compromised. If
>
>
>>ctor() inits B2, M1, and M2 and forwards to ctor( B1_t const&, M3_t
>>const &) then there is not ordering of actions in ctor()'s init list
>>that preserves the order of initialization of base classes and
>
> members.
>
>>it is not clear to me that this is particularly dangerous, but it
>
> does
>
>>create a trap for the unwary.
>
>
> It's still worse than being free to place your constructors in the
> order you prefer.

Not really. The feature we are discussing is in no sense mandatory. if
you want to order your ctors in a particular sequence you can do so and
not use sibling ctors for initialization. So it imposes no bruden on
those who do not make use of it.

>
>
>>>>But what is the worst thing that can happen? Someone writes a
>
> group
>
>>>>of ctors with a circular set of references. How is this badder (a
>>>>technical term) than permitting coders to write functions with a
>>>>circular set of references? Ctor init lists and calls to sibling
>>>>ctors can be just as conditional as mutual recursion or self
>>>>recusrsion in normal functions.
>>>
>>>It is worse because it is a gratuitous addition of a way to hurt
>>>oneself without a significant gain.
>>
>>I believe there is a gain. One might argue that recusrion in general
>
>
>>should be prohibited because in principle any design based upon
>>recusrion can be changed into one based upon iteration, which
>
> generally
>
>>makes the code clearer, but often more voluminuous.
>
>
> I do not, but you know that. By the way, in my experience designs based
> on recursion are often clearer than iterative ones, because they tend
> to be more abstract and because function calls hide explicit stack
> management. The only case where I find recursion less clear is when it
> is used to mimick explicit iteration.

Mostly I agree, but if the stacked objects are connected with pointers
of references I find the implicit management to be distracting and
prefer iteration.

/tj3

Trevor L. Jackson, III

unread,
Apr 1, 2005, 2:16:02 AM4/1/05
to
Gerhard Menzl wrote:

> Trevor L. Jackson, III wrote:
>
>
>>First, the usage interpretation of replace may in fact be the actual
>>meaning of the OP. And that could be considered a reasonable
>>suggestion. But I did not interpret it that way due to the context
>>wherein significant (and damaging) changes were made to the language
>>specifically for the purpose of achiving the usage replacement, with
>>implication that once manifest constants could be handled by the
>>language itself the need for the preprocessor would be reduced and
>>could be eliminated. I.e., usage change would be driven or forced by
>>language change.
>
>
> Can we agree that we don't want to remove #define from the language
> definition, and that I think people should be encouraged to reduce its
> use to an absolute minimum?

For me the anser depend upon the usage of #define. For code generation,
particularly conditional compilation it is essential. For manifest
constants it should be discouraged. For name agility (e.g., providing a
master namespace that can be easily adjusted to avoid collisions) there
is no alternative.

So it should not be used unless necessary. I think the point at issue
is that some people believe it can and should be completely eliminated.
That would be a problem because programmers would develop their own
code management tools external to the language and portability and
readability would suffer.

>
>
>>Now if you care to respond to my comments regarding your point about
>>scope limits I would be interested to hear your reaction.
>
>
> I have responded regarding scope in a different sub-thread and. Which
> point apart from this do you want me to respond to? I have lost track
> amid those undulating quotes.

I think you did respond in a separate message that I had not yet seen
when I wrote the above. So this subthread is done AFAICT.

/tj3

Gerhard Menzl

unread,
Apr 1, 2005, 9:30:54 PM4/1/05
to
Trevor L. Jackson, III wrote:

>>When it is said that the preprocessor does not respect scope, the term
>>is normally used in the sense of "declarative scope". Now you can
>>insist on calling the program text between a #define and its
>>corresponding #undef a scope and point to the heading of 16.3.5 which
>>reads "Scope of macro definition", but these preprocessor "scopes" are
>>completely orthogonal to and independent of declarative scopes as seen
>>by the compiler. Different terminology, same problem: the preprocessor
>>stomps over your source code like a herd of buffaloes.
>
> It may have that effect upon your source code, but it tends to improve
> mine. I suspect it depends upon the style and skill with which it is
> used.

You mean your source code is immune to preprocessor (re-)definitions?
Cool. What language do you program in? Or do you mean by "style and
skill" that you scan all in-house and third-party header files for
macros before including them and adapt your identifiers accordingly? And
by what magic do you prevent macros in third-party header files from
rendering code in other third-party header files incompilable?

> IMHO the preprocessor is like paint in that it covers the plaster and
> cracks betweent he drywall that bounds a room in the same sense that
> curly braces bound a declarative scope.

A colourful metaphor, but I can't figure out what it is supposed to mean
with regards to C++.

>>#undef is a cure that is hardly better than the disease.
>
> I disagree. Further discussion appears to be fruitless because you
> appear to have already made up your mind.

Regarding preprocessor macros, my mind has indeed come to rest at an
opinion that is backed up by experience and exchange of ideas with more
experienced peers. That does not mean that it will remain there
immovable until the end of time, but it will take much, much better
arguments than "I disagree" to convince me that I am wrong.

>>Until you come up with a compelling example proving the contrary, I
>>would boldly claim that whenever you feel the need to do such a thing,
>>you have got a big design problem.
>
> That can be said about any suggestion that the language has limits.
> So it doesn't mean much in any specific case. In this case it is flat
> our wrong.
>
> For example, it is common to compose complex type expressions using
> intermediate typedefs. Yet the convenience and clarity of temporary
> type declarations cannot be used to create a file-scope definition
> without also polluting the scope with what should be temporaqry type
> definitions.

I have never encountered the term "temporary type definition". Would you
care to explain it?

In case it is supposed to mean "a type definition that can be undefined
at any arbitrary point for the rest of the translation unit", I can but
say that I have never found the need for such a feature in 11 years of
programming in C++. Of course, that doesn't prove it is unnecessary in
general. To claim experience in every programming paradigm and problem
domain would be folly. I also do not remember anyone asking for an
untypedef feature in this newsgroup in the past seven years, and I know
of no discussion in the relevant literature. That still doesn't prove
anything: I don't read every single posting, there are books I have not
got around to delve into, and even the C++ community as a whole can fail
to perceive the need for novel features. But you really, really cannot
expect to be taken seriously unless you come up with at least one
compelling example that demonstrates the need to alter the language.
Sorry, but simply asserting that I am "flat out wrong" just doesn't cut
it. The burden of proof rests upon you, not upon the C++ community.

> That is not a big design problem. It is simply the nature of scoped
> symbols that lack explicit scope management. Claiming that all such
> limitations are actually the fault of the design is wrong and
> demonstrates a lack of comprehension of the issue.

I would think that it is rather a lack of explanation of the issue that
hinders the discussion.

>>Proper use of the declarative scopes defined by namespaces and classes
>>should eliminate any need to undeclare prematurely.
>
> Care to demonstrate how "proper use" would permit the use of temporary
> types to define a non-temporary type? I'll go so far as to suggest
> that you cannot do so. The best you can do is to put the temporary
> types into a tmp scope such as a namespace or a struct to hide them,
> but you will not be able to eliminate the symbol table pollution
> entirely unless of course you can eliminate the "big design problem"
> of the language rather than the code.

Of course I cannot do so until you explain what you mean by "temporary
type" and why you need them.

If I need a type exclusively within a class, I put the typedef into a
private section of the class definition, or into an unnamed namespace in
the implementation file. If I want other classes to have access, I make
it public. If the type cannot be attributed to a single class, I put it
into a suitable namespace. Where is the problem? What pollution do you
refer to? And why do you care about the symbol table? This is an
implementation detail of the compiler that is of no interest to me.
Finally, what is the "big design problem" of the language you are
talking about?

--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

Randy

unread,
Apr 1, 2005, 9:38:23 PM4/1/05
to

Trevor L. Jackson, III wrote:
>

[snip]

>
> And for all base classes and members it does not provide the automaic
> ordering that initialization lists provide.
>
>

> /tj3
>

Perhaps I mistake your meaning here, but initialization lists do NOT
provide any ordering. The order of initializations is determined by
the order of declarations, and not by the order in which the
initialization list is written.

See 12.6.2/5 for details.

Randy.

Trevor L. Jackson, III

unread,
Apr 2, 2005, 10:09:22 PM4/2/05
to
Randy wrote:
> Trevor L. Jackson, III wrote:
>
>
> [snip]
>
>
>>And for all base classes and members it does not provide the automaic
>>ordering that initialization lists provide.
>>
>>
>>/tj3
>>
>
>
> Perhaps I mistake your meaning here,

You do.

> but initialization lists do NOT
> provide any ordering.

They do, but "provide" is probably the wrong verb. Perhaps "conform to"
or "enforce" would have been better.

> The order of initializations is determined by
> the order of declarations, and not by the order in which the
> initialization list is written.

Right.

/tj3

Motti Lanzkron

unread,
Apr 3, 2005, 6:08:14 PM4/3/05
to
Nicola Musatti wrote:
>Aren't you forgetting 'volatile'?

I often do. Unfortunately you've snipped enough context so that I
don't know what you're referring to.

If you're referring to my suggestion that if the template parameter
for const_cast is omitted then it should default to "plain" T& or
"plain" T* (according to context), then no, I'm not forgetting
volatile. I think most uses of const_cast are for casting away
constness (this is my experience anyway) and it therefore would make a
good default, nothing prevents the user from explicitly specifying the
exact type const_cast should return.

Nicola Musatti

unread,
Apr 4, 2005, 12:06:18 PM4/4/05
to

Motti Lanzkron wrote:
> Nicola Musatti wrote:
> >Aren't you forgetting 'volatile'?
>
> I often do. Unfortunately you've snipped enough context so that I
> don't know what you're referring to.

You're right, sorry, Google Groups is pushing me into bad habits :-)

> If you're referring to my suggestion that if the template parameter
> for const_cast is omitted then it should default to "plain" T& or
> "plain" T* (according to context), then no, I'm not forgetting
> volatile. I think most uses of const_cast are for casting away
> constness (this is my experience anyway) and it therefore would make
a
> good default, nothing prevents the user from explicitly specifying
the
> exact type const_cast should return.

This is exactly what I was referring to.

Cheers,
Nicola Musatti

Gerhard Menzl

unread,
Apr 4, 2005, 12:02:40 PM4/4/05
to
Trevor L. Jackson, III wrote:

> For me the anser depend upon the usage of #define. For code
> generation, particularly conditional compilation it is essential. For
> manifest constants it should be discouraged. For name agility (e.g.,
> providing a master namespace that can be easily adjusted to avoid
> collisions) there is no alternative.

I cannot make any sense of the last sentence. What do you mean by "name
agility"? Since Google does not produce any meaningful search results, I
suspect that it is a private term of yours.

C++ provides you with a flexible namespace mechanism: nested namespaces,
using directives and declarations, namespace aliases, argument-dependent
lookup, etc. It is used successfully in projects of all sizes. I have
never heard from or met anyone who needs #define, of all constructs, for
namespace management. Why do you think you do?

There are but two uses of #define I find acceptable: header guards and
conditional compilation. The latter should be used judiciously in as few
places as possible, and preferably be moved to the makefile level.


--
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Nicola Musatti

unread,
Apr 6, 2005, 3:15:02 AM4/6/05
to

Trevor L. Jackson, III wrote:
> Nicola Musatti wrote:
[...]
> > This to me appears to be the same as never using initialization
lists
> > in constructors and put all "initialisation" code in the
constructor
> > bodies, thus solving all your problems in a much simpler way than
your
> > placement new technique.
>
> In some cases it is possible to assign each member within the object.
> However, while that is OK for built-in types and PODs, it does not
work
> well for objects. It does not work at all for base classes.
>
> And for all base classes and members it does not provide the automaic
> ordering that initialization lists provide.

While not very convenient, it can be made to work for base classes too;
you have to provide one or more init() functions that perform
initializations and, for those classes that can be both base classes
and concrete ones, a flag to mark the role currently played by the
class. If it's the last one in the inheritance chain, the init()
function is called in its constructor, otherwise it will be up to the
most derived class's constructor.

As for the order of initialization, in cases similar to the example you
posted earlier on, it would appear to be more inconvenient than
helpful, at least for the interdependent members.
[...]


> >>Wht is unclear or lacks rigor in the concept of using sibling ctors
> >>in initialization lists?
> >
> > The need to rely on code placement to enforce order of execution
> > constraints, or to give them up altogether.
>
> By order of execution do you mean order of init?

Exactly.

[...]


> >>I like Occam's Razor. YMMV.
> >
> >
> > So do I. Where mileage does vary is in what we consider to be
> > "purpose".
>
> If the factorization youi mentioned is a natural one for the object
it
> should be done without using init as a justification. If the
> factorization is only for the purposes of init then it is probably
> unnatural for the object and should not be done at all.

The need to initialize a subset of a class's subobjects in an
interdependent way is to me an indication that these members/base
subobjects are more cohesive among them than with the other members of
the class. This is enough for me to move them in a separate class. No
violation of Occam's Razor whatsoever.
[...]


> > It's still worse than being free to place your constructors in the
> > order you prefer.
>
> Not really. The feature we are discussing is in no sense mandatory.
if
> you want to order your ctors in a particular sequence you can do so
and
> not use sibling ctors for initialization. So it imposes no bruden on
> those who do not make use of it.

Programmers keep being burned by optional language features.

Cheers,
Nicola Musatti

Dave Harris

unread,
Apr 11, 2005, 7:35:12 PM4/11/05
to
jpo...@lhup.edu (John Potter) wrote (abridged):
> > I don't know, it just seems obvious to me. Whether an object can be
> > bound to a non-const reference should be orthogonal to whether
> > that object has a name. They are unrelated concepts.
>
> That is an amusing contradiction in C++. Objects without a name do not
> have an identity, address. It seems obvious to me that allowing member
> function calls with a this pointer and binding to const references are
> the illogical things.

To me the language seems hopelessly muddled in this area. Clearly objects
of class type do have a "this", whether or not they happen to be named.
Now that we have const/non-const, I'd like to get rid of rvalue/lvalue.


> Anyway, the history is that it was allowed, found to be a problem and
> removed from the language.

Yes. The problem was real, but a better fix could have been used (ie the
one proposed here).


-- Dave Harris, Nottingham, UK.

dave_abrahams

unread,
Apr 12, 2005, 3:02:00 AM4/12/05
to

Dave Harris wrote:
> jpo...@lhup.edu (John Potter) wrote (abridged):
> > > I don't know, it just seems obvious to me. Whether an object can
be
> > > bound to a non-const reference should be orthogonal to whether
> > > that object has a name. They are unrelated concepts.
> >
> > That is an amusing contradiction in C++. Objects without a name do
not
> > have an identity, address. It seems obvious to me that allowing
member
> > function calls with a this pointer and binding to const references
are
> > the illogical things.
>
> To me the language seems hopelessly muddled in this area. Clearly
objects
> of class type do have a "this", whether or not they happen to be
named.
> Now that we have const/non-const, I'd like to get rid of
rvalue/lvalue.

Fortunately that will never happen. With any luck, we are going to
strengthen the rvalue distinction by introducing rvalue references,
which enable an important category of optimization. If we got rid of
the notion of rvalue, we'd never get an effective move semantics.

--
David Abrahams
Boost Consulting
http://www.boost-consulting.com

It is loading more messages.
0 new messages