Topic: macros (was: namespaces: a real mess)


Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1998/06/29
Raw View
In article <m6al1.2030$z46.553023@newscene.newscene.com>,
alstevens@midifitz.com says...

[ ... ]

> You bet I do. But I wonder about all those programmers who don't get to read
> the standard. And I wonder how many compiler vendors are likely to put such
> warnings in their documentation: "Alert, the Surgeon General has determined
> that this compiler that you just paid a lot of money for produces undefined
> behavior if you do certain things."

I think any competent compiler vendor can be expected to do exactly
this.  For example, looking through the documentation for MS Visual
C++, I see it typically contains a statement about roughly what you
can expect portably (though it generally doesn't quote the standard
directly) typically followed by a section that's clearly labelled
"Microsoft Specific" telling you what they do in this particular
instance.

Looking through some (admittedly rather elderly) documentation from
Borland, I find a similar situation -- side-notes stating that (for
one example) "The conversions discussed in this section are specific
to Borland C++."  In their table of "modifiers", they show "constant"
and "volatile" followed by a heading "Borland C++ Extensions" followed
by a number more that it seems fairly clear to me aren't portable.

I'd also expect any competently written book in C or C++ to discuss
the fact that there are things you should NOT do, even though you
can't depend upon the compiler to diagnose them for you.  In some
cases, there are things that are perfectly legitimate in non-portable
code so some particular compiler (or perhaps almost any compiler on a
particular platform) is UNlikely to diagnose the code, even though
it's not at all portable.

Neither C nor C++ has ever had as one of the tenets of its design that
ALL code should be portable -- quite the contrary, it's been clearly
acknowledged since the beginning that they've long been used to write
things like device drivers, and that this is perfectly legitimate.
The standard simply defines what things you can depend upon being
portable, and what you can't.  While I'd expect it to be paraphrased
somewhat, any book that purports to teach either language should teach
the student the same thing.

--
    Later,
    Jerry.

The Universe is a figment of its own imagination.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/30
Raw View
  <35963360.FF345A85@acm.org> <5JOl1.4996$T7.826246@newscene.newscene.com>
X-NNTP-Posting-Host: petebecker.ne.mediaone.net
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: Mozilla 4.03 [en] (WinNT; U)
Content-Length: 1636
X-Status: $$$$
X-UID: 0000000001
Approved: stephen.clamage@sun.com (comp.std.c++)

Al Stevens wrote:
>
>
> >I don't see how "all identifiers" can be read to mean "identifiers that
> >the compiler uses".
>
> Neither would I when it is taken out of context. The paragraphs that precede
> that language begins with "Each header declares or defines all
> identifiers..." Also, it's important to observe that this language is in the
> Library section of the C Standard.

The section we're talking about has the title "Reserved Identifiers".
It's part of the library chapter, true, but it does not say that its
rules apply only to the library. For the benefit of the many programmers
who do not have access to the standard, make your own judgment about
whether this is "out of context". The "paragraphs that precede that
language" consist of the following sentence:

 Each header declares or defines all indentifiers listed in its
 associated section, and optionally declares or defines identifiers
 listed in its associated future library directions sections and
 identifiers which are always reserved either fore any use or for
 use as file scope identifiers.

That is, a header declares or defines all of the identifiers called for
in the standard library, and OPTIONALLY any others from the set of
reserved names. That sentence is followd immediately by the paragraph I
quoted earlier, which talks about "all identifiers" etc., that is, it
spells out what the set of reserved identifiers is.

>The section that defines identifiers makes no such restriction on identifers.

It also doesn't say in that section that keywords are reserved. That
does not mean that the restriction in the keywords section does not
apply.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/06/29
Raw View
Al Stevens wrote ...
>
>Take the preprocessor output from a MESSAGE_MAP expansion, pretty it up with
>tabs, and ask yourself if you really want to code that stuff every time you
>build a message map. Then try to achieve the same result, mapping a derived
>class member function to an event, by using a non-macro C++ construction.

std::map<event_id, ptr_to_member_function>

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
  "Remember when we told you there was no future? Well, this is it."
                                                        -- Blank Reg
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Al Stevens <alstevens@midifitz.com>
Date: 1998/06/29
Raw View
>Yes, the quote above is from the C standard. It doesn't use the word
"format".

No, I used the word so I wouldn't have to keep saying "identifiers that
start with an underscore and either an uppercase, blah, blah, blah"

>I don't see how "all identifiers" can be read to mean "identifiers that
>the compiler uses".

Neither would I when it is taken out of context. The paragraphs that precede
that language begins with "Each header declares or defines all
identifiers..." Also, it's important to observe that this language is in the
Library section of the C Standard. The section that defines identifiers
makes no such restriction on identifers.

>I don't need a Philadelphia lawyer here.

True, we're doing a good job of it ourselves. :-)

>> Of course. I think this point needed clarification in the C standard.
>
>How would you have worded it?

As the C++ standard worded it without the diagnostic language.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/29
Raw View
>std::map<event_id, ptr_to_member_function>

Interesting thought. If I take this concept any further, this might be where
I will start for custom mapping applications.

But that statement only declares the container. Initializing the container
with the function pointers is still going to be where the complexity lies.
As I recall (with my fading memory), it took typedefs and casts and implicit
class qualifications to coerce the compiler into initializing an array of
pointers to base class member functions with the address of member functions
of derived classes when there was no object instantiated yet. The macros hid
that complexity from the user. The template might reduce some of that
complexity.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW@my-dejanews.com
Date: 1998/06/27
Raw View
Sorry to respond to my own post, but there was a formatting error.

In article <6ms6n2$436$1@nnrp1.dejanews.com>, I wrote:
>
> In article <YG8k1.1034$u4.502233@newscene.newscene.com>,
>   "Al Stevens" <alstevens@midifitz.com> wrote:
> >
> > >CD2 2.10/2:
> > >2 In addition, identifiers containing a double underscore (__) or
> > >beginning with an underscore and an upper-case letter are reserved for
> > >use by C++ implementations and standard libraries and shall not be
> > >used otherwise; no diagnostic is required.
> >
> > There is such a thing as a compliant compiler. But a compliant program?
> > What's the penalty for noncompliance if there is no diagnostic? I wish there
> > was a diagnostic required. Compilers could be smart enough to suppress it
> > when they are looking at declarations in their own headers.
>
> There's an interesting thought.  But how would it work?
>
> For compilers on systems with heirarchical directory structures, it could
> give special treatment for headers in the compiler headers directory.  But
> what stops you from moving your third-party header file into that directory?
>
> The compiler could keep an internal list of header files.  So long as the
> file was on this list, there would be no problem.  But what if I had my
> own header file named "iostream.h" (remember -- there is no header file
> with this name mentioned in the spec).  Would it detect this error there?
> Also, the list of header files supplied with most compilers is starting to
> get rather large, what with the standard C library, the C++ library, and
> the STL.  The problem is even worse on most platforms, such as Windows,
> that supply their own header files, and even worse than that when the vendor
> supports extensions such as MFC or OWL...
>
> Perhaps we want the intersection of those two ideas -- only for headers in
> the compiler headers directory, and then only if it has a certain name.  I
> suppose modifying the header files that comes with the compiler is a thought
> too horrid to think of.  Besides, that couldn't happen by accident, and we
> want to protect against accident and not fraud.  But if we wanted to, we
> could take the CRC-16 of the entire header file.  Then only header files
> that had the right name and the right CRC-16, and were in the right
> directory, would supress the message. ...No, this is getting ugly.
>
> It could use a #pragma, which was present in every compiler-supplied header
> file.  Unlike most #pragmas I've used on purpose, this one would affect the
> current file but not the rest of the translation unit.  (There is a precedent
> for this in Microsoft, with the "#pragma once" for header files.)  Of course,
> the user could put this #pragma in her own program, but again, that couldn't
> happen by accident, so this one might work.
>
> Come to think of it, Microsoft already has defined a pragma to disable any
> warning, given it's message number.  So all they would have to do is to wrap
> the header files like this:

[Formatting restored]

>     #pragma warning(disable:9999)
>     // Header file guts go here
>     #pragma warning(default:9999)

> Where 9999 would be replaced with the new warning number.  (Currently
> Microsoft does not have a warning for use of identifiers reserved for
> library headers.)

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
>Perhaps because they felt it was too difficult for a compiler to
>distinguish between the names it uses (in its header files) and
>user-defined names?

Shouldn't be. I've written translators, and it would not have been that
difficult, but I can't speak for other translator authors. More likely, they
just didn't think it was worth the effort.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
>Some of the most important advice the standard provides to programmers
>is when it states that some coding practice may produce "undefined
>behavior"; usually no diagnostic is required. I don't know about you,
>but I pay very close attention to those passages.

You bet I do. But I wonder about all those programmers who don't get to read
the standard. And I wonder how many compiler vendors are likely to put such
warnings in their documentation: "Alert, the Surgeon General has determined
that this compiler that you just paid a lot of money for produces undefined
behavior if you do certain things."
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Al Stevens <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
> Which gets at exactly the difference between the two statements above.
>The first is advice to programmers. The second is a requirement on
>conforming programs. Requirements on conforming programs tell the
>programmer what can and cannot be done. If the programmer chooses to do
>something that violates the standard, even if a diagnostic is not
>required, the programmer cannot expect any particular behavior from that
>program.

I've said this before: Few programmers ever see the standard (referring, of
course, to the ones out there, not the ones who post here). Conforming
programs? Is there really such a thing?

>In any case, that decision was made nearly ten years ago. It's a bit late
to be questioning it now.


Never too late. Things have been changed that were older than that. Nothing
is sacrosanct.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
While we're brainstorming:

The standard could say that a diagnostic is required but not for compiler
headers and leave the solution up to the compiler vendor who could consider
solutions such as those you mentioned. Here's another one. Assuming the
compiler is installed by an installation program, the installation could add
a list to a system file (e.g. the Windows Registry) of the headers that are
installed and where they are installed. That could be the list. I wouldn't
worry about a user's iostream.h in the system directory. User's who do that
are asking for it.

End of brainstorm.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
> All identifiers that begin with an underscore and either an
> uppercase letter or another underscore are always reserved for
> any use.
>
>Sounds pretty clear to me: if you use such an identifier in your code
>you do not have a conforming program.

If your interpretation says you can't use the format, then it's not that
clear. I find a different interpretation. (Remember, we're talking about the
C standard here.) The identifiers that the compiler uses are reserved, not
the use of the underscore. I can validly interpret that language that way
irrespective of the intentions of its authors. I do not necessarily
interpret it the other way. If you do, then one of us is wrong, or there is
an ambiguity. Even your own sentence says, "if you use such an identifier in
your code..." Ok, I won't use one of those identifiers. (It's the difference
between saying "such as" and "like.") But I can use the underscore format
and still be complying. Now if you had said, "if you use an identifer that
uses the format..." which is what I think you meant and what the author of
the language might have meant... Whew. We need a Philadelphia lawyer here
and I don't qualify.

> Don't mess around with identifiers like this. You're asking for
>trouble.

Of course. I think this point needed clarification in the C standard. The
C++ standard clarified it, but then wimped out on the diagnostic question.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/28
Raw View
>But that's always true of all new features.  The "classes" in "C with
>classes were once new, and sure enough, there were people that resisted
>them for exactly that reason.

Which makes my point. Classes weren't written into a standard, formally
blessed, cast into stone, until after programmers had many years experience
using them, during which a lot of changes were made to make them work
better.

>But you should't argue against a feature just because it's a new feature.

I refer you to the book titled Up The Organization. One of its points was
that one person had the job of reacting to every new form (feature) by
standing in the middle of the office, holding the form over head, and
jumping up and down yelling "Horse****!" at the top of his lungs until
either someone justified the new thing or it went away. I think that is a
valid role for someone to play.

>Can you supply an example, and illustrate why it cannot be implemented
>without macros (or at least why this isn't feasible)?

I can refer you to a couple of books I co-authored that use that technique
for an event driven class library and then ask you to show me a more elegant
notation that does not use macros. That way you get to go through what I
went through and consequently you will be better convinced than if I just
tell you. (Besides, I'd have to repeat the pain because I kept only the part
that worked, not all the stuff I rejected). Believe me, because it was a
book for C++ programmers, I wanted as pure a C++ implementation as possible.
Sometimes the old tools work better.

Take the preprocessor output from a MESSAGE_MAP expansion, pretty it up with
tabs, and ask yourself if you really want to code that stuff every time you
build a message map. Then try to achieve the same result, mapping a derived
class member function to an event, by using a non-macro C++ construction.

I will admit that I did not try to solve this problem with templates because
they did not exist back then (nor did they when MESSAGE_MAP was first
conceived), and I would be interested in looking at a template based
solution. I have not thought any more about it than enough to write that
last sentence, so you could silence me by saying, "There is a template
solution you haven't considered." I'd have to go away and work on it to
answer, and I might some day, but not now. Even so, the MESSAGE_MAP syntax
is quite simple and I have doubts about seeing anything being better.

>> I think if you tried to implement this, you'd find that there are a lot of
>> casts and other favors that the message map macros do for you especially
>> with the pointers to member functions. I think you would find that the array
>> initializers would be quite complex. I went through this a couple of times
>> mapping events to derived class functions in event-driven class libraries,
>> and it is a mess. Macros were the solution.

>They are a mess when solved with macros, too.

But not for the programmers who use the macros. You deal with the mess once
and hide it from the users forever.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/28
Raw View
Al Stevens wrote:
>
> > All identifiers that begin with an underscore and either an
> > uppercase letter or another underscore are always reserved for
> > any use.
> >
> >Sounds pretty clear to me: if you use such an identifier in your code
> >you do not have a conforming program.
>
> If your interpretation says you can't use the format, then it's not that
> clear. I find a different interpretation. (Remember, we're talking about the
> C standard here.)

Yes, the quote above is from the C standard. It doesn't use the word
"format".

> The identifiers that the compiler uses are reserved, not
> the use of the underscore.

I don't see how "all identifiers" can be read to mean "identifiers that
the compiler uses".

> I can validly interpret that language that way
> irrespective of the intentions of its authors.

So far you haven't said anything about which words and constructs in
that sentence lead you to think that it says what you say it does.

> I do not necessarily
> interpret it the other way. If you do, then one of us is wrong, or there is
> an ambiguity. Even your own sentence says, "if you use such an identifier in
> your code..." Ok, I won't use one of those identifiers. (It's the difference
> between saying "such as" and "like.") But I can use the underscore format
> and still be complying. Now if you had said, "if you use an identifer that
> uses the format..." which is what I think you meant and what the author of
> the language might have meant... Whew. We need a Philadelphia lawyer here
> and I don't qualify.

I don't need a Philadelphia lawyer here. The words have an obvious
meaning: "all indentifiers" does not mean "all identifiers that the
compiler uses". "that begin with an underscore ... and an uppercase
letter..." means just what it says. "reserved for any use" means that a
conforming program cannot use them. Which part of this do you disagree
with?

>
> > Don't mess around with identifiers like this. You're asking for
> >trouble.
>
> Of course. I think this point needed clarification in the C standard.

How would you have worded it?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/28
Raw View
Al Stevens wrote:
>
> > Which gets at exactly the difference between the two statements above.
> >The first is advice to programmers. The second is a requirement on
> >conforming programs. Requirements on conforming programs tell the
> >programmer what can and cannot be done. If the programmer chooses to do
> >something that violates the standard, even if a diagnostic is not
> >required, the programmer cannot expect any particular behavior from that
> >program.
>
> I've said this before: Few programmers ever see the standard (referring, of
> course, to the ones out there, not the ones who post here). Conforming
> programs? Is there really such a thing?

Fine. I'll rephrase it:

 Requirements on conforming programs tell the programmer who has
 read and understood the pertinent parts of the standard, or who
 has read and understood descriptive materials written by
 somebody familiar, directoy or indirectly, with the pertinent
 parts of the standard, what can and cannot be done. If a
 programmer who has read and understood the pertinent parts of
 the standard, or who has read and understood descriptive
 materials written by somebody familiar, directly or indirectly,
 with the pertinent parts of the standard, chooses to do
 something that violates the standard, even if a diagnostic is
 not required, the programmer cannot expect any particular
 behavior from that program.

The thing is, if you fully qualify every statement in order to make
contextual assumptions explicit you end up with a statement that's at
least two or three times longer than the original. The C standard could
have imposed requirements in all cases where no diagnostic is currently
required. The standard would have taken longer to write and been larger.
Compilers that diagnosed those edge cases would be bigger and slower.
The decision was to not do that, but just to describe what those edge
cases are, so that programmers can stay away from them. Of course,
programmers being programmers, this is viewed as a challenge, so they
try to see how close they can get to the edge without falling off. And,
programmers being programmers, far too many fall off.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Marcelo Cantos <marcelo@janus.mds.rmit.edu.au>
Date: 1998/06/28
Raw View
Pete Becker <petebecker@acm.org> writes:

> I don't need a Philadelphia lawyer here. The words have an obvious
> meaning: "all indentifiers" does not mean "all identifiers that the
> compiler uses". "that begin with an underscore ... and an uppercase
> letter..." means just what it says. "reserved for any use" means
> that a conforming program cannot use them. Which part of this do you
> disagree with?

The ambiguity is fairly obvious to me.  For whom are they reserved,
implementations or programmers?  If the statement had been, "reserved
for use by implementations," that would have been abundantly clear.
However, "for any use," begs the question, "by whom??"


Cheers,
Marcelo

--
______________________________________________________________________
Marcelo Cantos, Research Assistant       __/_  marcelo@mds.rmit.edu.au
Multimedia Database Systems Group, RMIT   /       _ Tel 61-3-9282-2497
L2/723 Swanston St, Carlton VIC 3053, Aus/ralia ><_>Fax 61-3-9282-2490
Acknowledgements: errors - me; wisdom - God; sponsorship - RMIT
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: miker3@ix.netcom.com (Michael Rubenstein)
Date: 1998/06/28
Raw View
On 28 Jun 98 14:37:46 GMT, Marcelo Cantos
<marcelo@janus.mds.rmit.edu.au> wrote:

>Pete Becker <petebecker@acm.org> writes:
>
>> I don't need a Philadelphia lawyer here. The words have an obvious
>> meaning: "all indentifiers" does not mean "all identifiers that the
>> compiler uses". "that begin with an underscore ... and an uppercase
>> letter..." means just what it says. "reserved for any use" means
>> that a conforming program cannot use them. Which part of this do you
>> disagree with?
>
>The ambiguity is fairly obvious to me.  For whom are they reserved,
>implementations or programmers?  If the statement had been, "reserved
>for use by implementations," that would have been abundantly clear.
>However, "for any use," begs the question, "by whom??"

The C++ [draft] standard does say that they are reserved for use by
implementations (2.10):

 ... identifiers containing a double underscore (__) or
 beginning with an underscore and an upper-case letter are
 reserved for use by  C++  implementations  and standard
 libraries and shall not be used otherwise; no diagnostic is
 required.

The C standard also makes it clear that they are reserved for the
implementation by saying that declaring or defining a reserved
identifier (other than as allowed in the the standard) results in
undefined behavior:

 - All identifiers that begin with an underscore and either an
 uppercase letter or another underscore are always reserved for

 any use.

 ...

 ... If the program declares or defines an identifier with the
` same name as an identifier reserved in that context (other
 than as allowed by 7.1.7), the behavior is undefined.
--
Michael M Rubenstein
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/25
Raw View
>That's probably because "shall be avoided by users" is meaningless in a
>language standard.

So is "and shall not be used otherwise" particularly when "no diagnostic is
required" and most particularly when the purpose of a language standard is
that it "specifies requirements for processors of the C++ programming
language" and not rules for programmers to follow. I don't see how a
language standard can mandate what a programmer codes unless the language
standard mandates that the compiler at least complain about it.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1998/06/25
Raw View
Daniel Parker<danielp@nospam.com> wrote:
>
>  I hasten to add that I often need to follow Nathan
>Myers's excellent advice of
>
>#ifdef min
>#undef min
>#endif
>
>and I've had to abandon using uppercase letters for enumeration constants
>because of the pollution of the namespace by short macro names.

Sorry, my current advice is to write:

  #undef min

Are there any compilers that warn about #undef of something not defined?

--
Nathan Myers
ncm@nospam.cantrip.org  http://www.cantrip.org/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: AllanW@my-dejanews.com
Date: 1998/06/25
Raw View
In article <HYek1.341$sV4.124405@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
>
> I'm not arguing that pre-namespace code is better. Only that it is better
> understood because we have some experience with it. And maybe that it is not
> worse, although I haven't seen all the code in the world.

But that's always true of all new features.  The "classes" in "C with
classes were once new, and sure enough, there were people that resisted
them for exactly that reason.

But you should't argue against a feature just because it's a new feature.
At some point a new feature has to become a feature, and we use it as
such, applying it where it is useful, and not where it is not.

> >> >about _GetMin() and _GetMax(), or __GetMin() and __GetMax()?
>
> That's still OK. The C standard does not disallow this or even discourage it
> except through implication. All that is reserved are the names that the
> compiler vendor puts in their headers with that format. It's about names,
> not underscores.

That's my point exactly.  The use of any name like this, that the compiler
vendor COULD use but currently does NOT use, could cause potential problems
on ANY other compiler, including the next version of the same compiler.
And that's even if we ignore the macro problem, which is where this
discussion started.

> The C++ standard goes a little farther and says you can't
> use those formats, but nothing bad happens if you do.

I suspect that the reason is what I explained above.

> >Which raises the question: why not use _getMin() and _getMax()?  They
> >start with a single underscore and do NOT have a capital letter.  Couldn't
> >they be used safely?
>
> As safely as any other name.

Yes, exactly!  But in the potential presence of unknown macros in some
other organization, none of the other names are safe either!  Even
completely "normal" member names can be a problem if the programmer is
free to declare macros with any name desired.  Remember that ALL_CAPS
is a convention, not a requirement.  Since the legal macro names consume
100% of the legal identifier names, there is nothing left guaranteed to
work correctly in any header file used in an unknown environment.

> >BEGIN_MESSAGE_MAP is a macro that generates both some member
> >function definitions and some data definitions.  And yet, at least IMHO,
> >it still hasn't demonstrated why a macro is NEEDED.  (Perhaps if the
> >macro call was hand-crafted you could convince me that it's less error
> >prone, but it isn't, so it isn't.)  There may be more complex, contrived
> >examples that don't shift into non-macro code so easily, but I think you'll
> >have a tough time finding them, and I doubt they'll be real-world.
>
> Think about the idiom, not the particular example I chose (although I
> disagree that your example is as readable as the message map, what I am used
> to notwithstanding). I won't have a tough time finding other examples
> because I have used the idiom in several, non-contrived ways to map things
> that would be unwieldy with non-macro C++ constructs, and they were quite
> real-world.

Can you supply an example, and illustrate why it cannot be implemented
without macros (or at least why this isn't feasible)?

> >    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
> >        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
> >        // ...
> >        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
> >    };
>
> I think if you tried to implement this, you'd find that there are a lot of
> casts and other favors that the message map macros do for you especially
> with the pointers to member functions. I think you would find that the array
> initializers would be quite complex. I went through this a couple of times
> mapping events to derived class functions in event-driven class libraries,
> and it is a mess. Macros were the solution.

They are a mess when solved with macros, too.  Currently macros hide the
mess; the non-macro answer would hide the mess in a template constructor
for AFX_MSGMAP_ENTRY.

[Previous context restored from other messages]:
> > > > > Inline functions don't totally replace #define macros either.
> > > > > There is a cost in memory and processing time. Compare the
> > > > > underlying assembly code of the two idioms for a simple function
> > > > > with arguments. To preserve the "caller's" copy of the argument
> > > > > and avoid side effects, the C++ inline function pushes arguments
> > > > > on the stack and uses copies. The macro does not.

> > > > On what compiler is this always true?  A standards-conforming
> > > > compiler would do this when it's required, but not when it isn't.
> > > > After all, some inline functions are supposed to alter the
> > > > "caller's" copy of the argument, and are supposed to propogate
> > > > side effects.

> > > VC++ 5.0 with optimizations turned off for one example. I posted
> > > about that behavior in another response. It's an implementation
> > > issue, not a language issue.

> >With optimizations turned off?  Is that really fair?
>
> Probably not. You asked for an example. I grabbed the closest one (all
> that's installed here). I've seen the behavior in older compilers, but you
> might be right; by now they might all do a proper job of inlining and
> optimizing. But why should I trust the latest compiler?

Because you want the latest C++ features.  If you don't want that, then
continue to use an older compiler -- but that isn't really the point of
any post in comp.std.c++, is it?

> Perhaps holy grails like type-safety and avoidance of side-effects

Are these "holy grails" in the sense that they are unattainable?  Even if
that were so, I would argue that the language should get as close as is
reasonably possible to these goals -- and, in fact, I believe that the
latest draft standard is pretty dang close.

> are important for new programmers or careless programmers or
> programmers who don't take time to learn their tools,

Are such programmers the only ones that ever make this type of mistake?
Is it possible for a seasoned professional programmer to be so careful
as to NEVER make this type of mistake, even for a second, and yet still
be productive enough to be employable?  Because if you ever spent even
one hour tracking down a bug caused by an unwanted side effect from a
macro expansion, then the new feature should have value for you.

> but #define is a tool, I know how it works,

We've locked horns on this before.  The need or desire for new language
features does not mark a poor programmer.  I know a lot about how to
use macros, having used them more than once in very productive ways.
I make the best use possible from language features that I have.  Further,
the more I use and understand these features, the more I can see how new
features would help even more.

Case in point.  In the early 1980's I switched from a BASIC interpreter to
a BASIC compiler, which required all variables to be declared before they
were used.  At the time, I was naive enough to think that this extra
"burden" was because of stricter requirements of the compiler.  Only
gradually did I recognize what so many know by now -- requiring declarations
(as C and C++ have always done) allows the compiler to catch every instance
of a certain type of bug at compile time, instead of forcing the programmer
to find it in the debugger.

I was a fairly good programmer at the time; I rarely made that type of bug,
and I was excellent at finding it in the debugger when it did happen.  But
now I am a better programmer because that type of bug never even makes it
to the debugging stage -- it's stripped out as soon as I compile.

The same exact type of tradeoff is happening right now with macros compared
to inline functions.  You don't like it because it's new, and since you
never needed it in the past you think you don't need it now.  Perhaps you
are right, but I can tell you that as soon as I was satisfied that my
compiler implemented it correctly, I started using it heavily, and so far
I have not had occasion to regret that decision.

> and I'll continue to use it when I want it.

And I would defend your right to do so.  But check out some of the newer
features too, and I think you will see that they do have value.

> (But I don't teach its use, so kick me.)

Sure, if it will help! 8^)

> >they are never superior to other equivalent methods
>
> That's a safe statement. How could anything be superior to its equal? :-)

Equivalent does not neccesarily mean equal.  Consider calling a function
that takes a reference argument, or one that takes a pointer instead.
Surely these are equivalent, but I doubt that you would consider them
equal.

...or are references too new for you to consider them useful?  :-p

> > except for conditional compilation and compiler-defined constants.
>
> And functions that compilers refuse to inline.

Yes, that's true.  If you have a function that you absolutely insist MUST
be inlined, and yet the compiler refuses to inline it, I would agree that
you have made a case for using a macro.  For that one function.  Although
I might check two or three extra times to see if you really MUST have the
function inlined.  (Some programmers -- not you, of course, but some mere
mortals :-], think that certain functions must be inlined when in
reality it isn't all that important.)


-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/26
Raw View
Al Stevens wrote:
>
> >That's probably because "shall be avoided by users" is meaningless in a
> >language standard.
>
> So is "and shall not be used otherwise"

No. Note the difference: the first says it's OK to use them, but frowned
upon. The second says it is not allowed.

> particularly when "no diagnostic is
> required" and most particularly when the purpose of a language standard is
> that it "specifies requirements for processors of the C++ programming
> language" and not rules for programmers to follow. I don't see how a
> language standard can mandate what a programmer codes unless the language
> standard mandates that the compiler at least complain about it.

 Which gets at exactly the difference between the two statements above.
The first is advice to programmers. The second is a requirement on
conforming programs. Requirements on conforming programs tell the
programmer what can and cannot be done. If the programmer chooses to do
something that violates the standard, even if a diagnostic is not
required, the programmer cannot expect any particular behavior from that
program. They also tell implementors what they must worry about getting
right and what they need not pay attention to. Not having to diagnose
two modifications of the same object without an intervening sequence
point, for example, makes it much easier to write compilers. Part of the
goal of a standard is to make it possible to implement the language with
a reasonable amount of effort. In any case, that decision was made
nearly ten years ago. It's a bit late to be questioning it now.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/06/26
Raw View
[Talking about reserved identifiers...]

>> That's probably because "shall be avoided by users" is meaningless in
>> a language standard.

Al Stevens wrote:
> So is "and shall not be used otherwise" particularly when "no
> diagnostic is required" and most particularly when the purpose of a
> language standard is that it "specifies requirements for processors of
> the C++ programming language" and not rules for programmers to follow.
>
> I don't see how a language standard can mandate what a programmer
> codes unless the language standard mandates that the compiler at least
> complain about it.

Perhaps because they felt it was too difficult for a compiler to
distinguish between the names it uses (in its header files) and
user-defined names?

-- David R. Tribble, david.tribble@central.beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/06/27
Raw View
AllanW@my-dejanews.com wrote:

[...]

> But if they chose to and there's no conflict, they can use std once in the
> whole compilation unit.  And most of the time there won't be a conflict.
> (So then why use namespaces at all?  Because pre-namespaces, if there
> was a conflict, there was nothing to do about it.  But with the "using
> namespace std" method, if there's a conflict, all they have to do is remove
> the using directive and fix the references to be explicit.)

I think you'd not even be forced to remove using namespace std; you
just had to prefix the conflicting names, say:

#include <iostream> // has std::clog
#include <whatever> // has whatever::clog

using namespace std;
using namespace whatever;

int main()
{
  cout << "Hello world" << endl; // Ok: no cout in namespace whatever
  somewhateverfunction(); // Ok no such fn in namespace std;
  clog << "Test"; // Error: amiguity between std::clog and
whatever::clog
  std::clog << "Test"; // Ok: explicit qualification
  whatever::clog("xyz"); // dito
}
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/06/27
Raw View
Al Stevens wrote:
>
> >That's probably because "shall be avoided by users" is meaningless in a
> >language standard.
>
> So is "and shall not be used otherwise" particularly when "no diagnostic is
> required" and most particularly when the purpose of a language standard is
> that it "specifies requirements for processors of the C++ programming
> language" and not rules for programmers to follow. I don't see how a
> language standard can mandate what a programmer codes unless the language
> standard mandates that the compiler at least complain about it.

Some of the most important advice the standard provides to programmers
is when it states that some coding practice may produce "undefined
behavior"; usually no diagnostic is required. I don't know about you,
but I pay very close attention to those passages.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Christopher M. Gurnee" <gurnec@nospam.yahoo.com>
Date: 1998/06/23
Raw View
Al Stevens wrote in message ...
<snip>
>That's a common misinterpretation of the C standard. The C standard doesn't
>say that at all (unless it's tucked away in some obscure place not reachable
>from the index or TOC). No where does the standard prohibit programmers from
>using underscores as the first character of identifiers. It says that all
>identifiers in standard library headers that begin with an underscore and
>either a second underscore or an upper case letter are reserved identifiers
>and that all identifers in standard library header files that begin with an
>underscore and are in file scope are reserved identifers in that file scope.
>It's about reserved identifiers, not reserved use of leading underscores.
>But what those identifiers are is up to the compiler vendor. So a smart
>programmer would interpret that and conclude that it is not a good idea to
>use an underscore to begin an identifier because a future version of the
>compiler library might reserve the same identifier. Thus evolved a
>convention, but no such rule ever existed.
<snip>

I don't really want to get in the middle of this namespace battle :)
but here's that hidden paragraph you missed.

CD2 2.10/2:
2 In addition, identifiers containing a double underscore (__) or
beginning with an underscore and an upper-case letter are reserved for
use by C++ implementations and standard libraries and shall not be
used otherwise; no diagnostic is required.

-Chris Gurnee



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/06/24
Raw View
In article <DrPj1.27929$08.7035062@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
>
> >No, namespaces aggrevate the existing problem with macros.
>
> Perhaps you should modify that to say, "...the perceived problem with
> macros."

Agreed.

> Believe it or not, there are those of us who have no problem with
> macros when properly used.

Oh, I believe it.  It isn't exactly common for me either -- it's happend only
on four occasions in my 6 years with the language, not counting the learning
curve when I was a C and C++ novice.  However, for two of those occasions,
finding and fixing the problem was very expensive.

> That might be the consequence of long years of
> experience with the idiom and its idiosyncrasies, experience that has
> evolved into understanding,

Absolutely required for professional-level programming, including the use of
macros.  Beginners stumble into the "macro problem" frequently; but once
we've learned better, we avoid it when reasonable.

But also demonstrates at least a small amount of luck, I hope you'll agree.

> the kind of understanding that no one has with
> some of the newer parts of C++. Any code idiom can be abused and no code
> idiom can prevent its own abuse from abusing programmers.

I disagree with the wording, but I agree with the principle.  I've worked with
a language that had an "iron-fist" approach, with rules that couldn't be
abused.  I found that I couldn't be expressive, either; that was some of the
worst work of my professional life, in almost every sense (least fun, worst
results).  I plan to never work with that language ever again.

> >Forget namespaces for a moment.
>
> Would that I could.

Heh, that's pretty funny...

> >...you can't assume
> >that the user isn't using some ancient C-language header file that was
> >included before yours.
>
> A common problem that nothing new about namespaces or old about
> macros or old or new about anything else is going to solve.

I beg to differ.  Almost any reasonable use of namespaces, coupled with
minimal (or better yet, no) use of macros, should reduce this problem to very
near zero, even by the standards of those C and C++ novices that haven't
learned to avoid the hotspots.

> The nice thing about old
> header files and their old macros is that if they are really badly done, you
> can change the header file macros without harming the library that was
> compiled with them. (You can't do that with namespaces.)

Thereby solving 1/2 the problem.  But we still have to deal with global
non-prefix function names like "SendMessage".

Still, you're not really suggesting that pre-namespace code is better
because you can fix what's badly done, are you?  I wouldn't use that as
a justification for anything less than a source license -- and beware of
that too.  (Poor header files may indicate poor source modules, which
probably isn't where you want to spend a lot of money.)

> When dealing with
> "ancient C-language header file[s]" you don't usually have to worry about
> version control and product upgrades and retrofitting your corrections.
> Mind, I don't preach that practice, but I have been known to practice it.

Agreed.  That's why I think putting a version number in a namespace name
is a bad idea.  Either the new names are compatible with the old, in which
case no new namespace name is needed, or they are not, in which case
you realistically have to re-compile most or all calling modules anyway.

> >What about _getMin() and _getMax(), or __getMin() and __getMax()?  The
> >Standard-C or Standard-C++ programmer isn't supposed to use names like
> >this for macros or any other identifier -- they're reserved for the compiler's
> >use only.
>
> That's a common misinterpretation of the C standard. The C standard doesn't
> say that at all (unless it's tucked away in some obscure place not reachable
> from the index or TOC). No where does the standard prohibit programmers
> from using underscores as the first character of identifiers. It says that all
> identifiers in standard library headers that begin with an underscore and
> either a second underscore or an upper case letter are reserved identifiers
> and that all identifers in standard library header files that begin with an
> underscore and are in file scope are reserved identifers in that file scope.
> It's about reserved identifiers, not reserved use of leading underscores.
> But what those identifiers are is up to the compiler vendor. So a smart
> programmer would interpret that and conclude that it is not a good idea to
> use an underscore to begin an identifier because a future version of the
> compiler library might reserve the same identifier. Thus evolved a
> convention, but no such rule ever existed.

Sorry, I misspoke.  (Mis-typed?)  What I should have written is,

> >about _GetMin() and _GetMax(), or __GetMin() and __GetMax()?

etc.

However, the argument still stands.  Saying that it's allowed, although the
compiler might use it for something incompatible, is less than bright when
working with one compiler.  It seems fine for now, but then so is everything
else marked "non-portable."  As you pointed out, the next version of the
same compiler might use one of your symbols for something internal.  But
if you want to be portable to other compilers or other platforms, then you
have to say it even stronger: Do not use these names, because you
can't know that they will work.  (Unless you form an absolute list of every
version of every compiler that you ever intend to support, and test it on
every one of them separately -- this might be feasible for every current
version, but not for every version ever!)

Which raises the question: why not use _getMin() and _getMax()?  They
start with a single underscore and do NOT have a capital letter.  Couldn't
they be used safely?  And the answer is that any name you could use as
a library vendor, without conflicting with the compiler, the programmer could
also use without conflicting with the compiler.  So at least in theory, the
names _getMin() and _getMax() aren't any better than getMin() and getMax().

It's all a giant circle.  Within the range of legal identifiers, some are
reserved for use by the compiler, and all the others are legal for use by the
programmer. There are no identifiers reserved for use by third-party
libraries.  (And even if there were, what happens in programs that use two or
more libraries?)

> >Besides, how do you explain to your users that they have
> >to shove underscores in the middle of every member-function call they
> >make?
>
> The same way you explain to them that they now have to use std::.

But if they chose to and there's no conflict, they can use std once in the
whole compilation unit.  And most of the time there won't be a conflict.
(So then why use namespaces at all?  Because pre-namespaces, if there
was a conflict, there was nothing to do about it.  But with the "using
namespace std" method, if there's a conflict, all they have to do is remove
the using directive and fix the references to be explicit.)

> >is just too ugly for words.
>
> ....the eye of the beholder.

Agreed.  But there is an innate elegance to this method that this beholder
likes.

The bottom line is, you're right -- nobody has very much experience with
namespaces yet, at least not in the problem domain they're designed to
solve.  But I can tell you that I've had experience with the problem itself,
and I hated it.  And it sure looks to me like this will resolve it, especially
when library vendors start using it.

Namespaces solve name clashes by declaring only ONE namespace name
for the whole library; it's a lot easier to pick ONE conflict-free name (say
CompanynameEmailPackage) than it is to pick a unique prefix that isn't
too rediculous (like the "cep" in cepSend(), cepReceive(), etc.)

One could argue that it's possible to specify
    CompanynameEmailPackageSend(),
    CompanynameEmailPackageReceive(),
etc., but in practice we know that no library works this way -- it's just too
unwieldy.  But namespace aliases allow the customer to do the equivalent
automatically, avoiding the very long name without tying them down to
what short name they can use.  That's simple and elegant, and should
work quite nicely -- not always, but much more often than prefixes or
anything else I've been offered.

Unfortunately, there is still one thing that interferes with this otherwise
simple and elegant solution: macros.

> >Don't you dare point to MFC macros as a shining example of the way things
> >should work!
>
> I don't believe I did that, but I also don't believe that you get to tell me
> what I dare not say. :-)
>
> >    BEGIN_MESSAGE_MAP(derived, base)
> >        ON_COMMAND_EX(ID_FILE_OPEN, OnFileOpen)
> >        // ...
> >    END_MESSAGE_MAP()
> >
> >we would have
> >
> >    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
> >        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
> >        // ...
> >        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
> >    };
>
> With all due respect, the former is, to this old eye, more readable and less
> ugly.

You're used to it.  Frankly, so am I.  But the two forms have very nearly
identical complexity, and besides that we're talking about code that is
generally written by a code generator.

Tthe original context was to demonstrate that we could do away with macros
as a substitute for inline functions.  You cited MFC message maps as a
valid exception, but I'm showing that it isn't a valid exception.

BEGIN_MESSAGE_MAP is a macro that generates both some member
function definitions and some data definitions.  And yet, at least IMHO,
it still hasn't demonstrated why a macro is NEEDED.  (Perhaps if the
macro call was hand-crafted you could convince me that it's less error
prone, but it isn't, so it isn't.)  There may be more complex, contrived
examples that don't shift into non-macro code so easily, but I think you'll
have a tough time finding them, and I doubt they'll be real-world.

> >On what compiler is this always true?
>
> VC++ 5.0 with optimizations turned off for one example. I posted about that
> behavior in another response. It's an implementation issue, not a language
> issue.

With optimizations turned off?  Is that really fair?

Turning off VC++ optimizations, among other things, causes inline functions
to be called out-of-line.  The usual reason for doing this is to make
debugging easier; the only other good reason is if you believe that the
optimizer might introduce errors (i.e. if it doesn't detect some aliasing).
By contrast, function-like macro expansion couldn't be automatically turned
into callable functions, so it never enjoys this "benefit."

I tried it myself:
    inline void FUNC(int &a,const int&b) { a+=b; }
    #ifndef _DEBUG // _DEBUG is defined for non-optimized builds
        #define MAC(a,b) ((a)+=(b)) // Optimized only
    #else
        void MAC(int&a,int&b) { a+=b; } // Non-optimized only
    #endif

    int main() {
        int a=5,b=7;
        FUNC(a,b);
        MAC(a,b);
        return 0;
    }

Optimized builds produced this:
    8:    int main() {
    00401000 33 C0                xor         eax,eax
    00401002 C3                   ret
[ Wow!  I was using VC++, not Ronko! ]

Non-optimized builds produced this:
    8:    int main() {
    0040AE24 55                   push        ebp
    0040AE25 8B EC                mov         ebp,esp
    0040AE27 83 EC 08             sub         esp,8
    9:        int a=5,b=7;
    0040AE2A C7 45 FC 05 00 00 00 mov         dword ptr [a],5
    0040AE31 C7 45 F8 07 00 00 00 mov         dword ptr [b],7
    10:       FUNC(a,b);
    0040AE38 8D 45 F8             lea         eax,[b]
    0040AE3B 50                   push        eax
    0040AE3C 8D 4D FC             lea         ecx,[a]
    0040AE3F 51                   push        ecx
    0040AE40 E8 BB 61 FF FF       call
        @ILT+0(?FUNC@@YAXAAHABH@Z)(0x00401000)
    0040AE45 83 C4 08             add         esp,8
    11:       MAC(a,b);
    0040AE48 8D 55 F8             lea         edx,[b]
    0040AE4B 52                   push        edx
    0040AE4C 8D 45 FC             lea         eax,[a]
    0040AE4F 50                   push        eax
    0040AE50 E8 B5 61 FF FF       call
        @ILT+10(?MAC@@YAXAAH0@Z)(0x0040100a)
    0040AE55 83 C4 08             add         esp,8
    12:       return 0;
    0040AE58 33 C0                xor         eax,eax
    13:   }
    0040AE5A 8B E5                mov         esp,ebp
    0040AE5C 5D                   pop         ebp
    0040AE5D C3                   ret
It shouldn't be surprising that the former macro call, now an out-of-line
function, generates the same code as the former inline function, now
an out-of-line function.  The two versions of the function are the same,
except for the ignored keyword "inline."

I still feel that although macros can be expedient, they are never superior
to other equivalent methods, except for conditional compilation and
compiler-defined constants.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/24
Raw View
>CD2 2.10/2:
>2 In addition, identifiers containing a double underscore (__) or
>beginning with an underscore and an upper-case letter are reserved for
>use by C++ implementations and standard libraries and shall not be
>used otherwise; no diagnostic is required.

You are quoting from the C++ standard are you not? I do not find that in the
C standard, which I was discussing. But looking back, I see that I was
responding to a post about both, so I'll modify my position and retract that
statement.

Incidentally, that language is stronger than the December 96 draft, which
says "and shall be avoided by users."

But the clause gives me pause. Most programmers do not use the Standard to
learn how to program in C++. Inasmuch as no diagnostic is required, it's the
same as no rule at all since it is not enforced and nobody reads it. You
cannot say, "and shall not be used otherwise" unless you have the juice to
back it up. "Shall" is a strong word usually reserved for commandments.
There is such a thing as a compliant compiler. But a compliant program?
What's the penalty for noncompliance if there is no diagnostic? I wish there
was a diagnostic required. Compilers could be smart enough to suppress it
when they are looking at declarations in their own headers.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1998/06/24
Raw View
In article <DrPj1.27929$08.7035062@newscene.newscene.com>,
alstevens@midifitz.com says...

[ ... ]

> That's a common misinterpretation of the C standard. The C standard doesn't
> say that at all (unless it's tucked away in some obscure place not reachable
> from the index or TOC). No where does the standard prohibit programmers from
> using underscores as the first character of identifiers. It says that all
> identifiers in standard library headers that begin with an underscore and
> either a second underscore or an upper case letter are reserved identifiers
> and that all identifers in standard library header files that begin with an
> underscore and are in file scope are reserved identifers in that file scope.

It says ($7.1.3):

    - All identifiers that begin with an underscore and either an
      uppercase letter or another underscore are always reserved for
      any use.

    - All identifiers that begin with an underscore are always
      reserved for use as identifiers with file scope in both the
      ordinary and tag name spaces.

As such, it's perfectly legal to use names that start with an
underscore, as long as it's not at file scope, and the underscore is
followed by a lower case letter or a digit.  (IIRC, it may also be
legal to follow it by a '$' as well, but that's covered in a normative
addendum or somesuch, which I don't have a copy of to check.)

However, that only applies to C -- in C++, the rule is a bit more
restrictive ($2.10 [lex.name], paragraph 2):

    In addition, identifiers containing a double underscore (_ _) or
    beginning with an underscore and an upper-case letter are
    reserved for use by C++ implementations and standard libraries and
    shall not be used otherwise; no diagnostic is required.

In particular, note that in C++, putting a double underscore ANYWHERE
in the identifier, not just the beginning, makes the identifier
reserved.  This is an example of the problems noted elsewhere with
macros: they form (almost?) the only excuse for this restriction on
identifiers -- if there were no macros to contend with, the names
would all be in namespaces, and the user would be able to use names
like this with impunity.

--
    Later,
    Jerry.

The Universe is a figment of its own imagination.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/25
Raw View
Al Stevens wrote:
>
> Incidentally, that language is stronger than the December 96 draft, which
> says "and shall be avoided by users."

That's probably because "shall be avoided by users" is meaningless in a
language standard.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/25
Raw View
>Still, you're not really suggesting that pre-namespace code is better
>because you can fix what's badly done, are you?

I'm not arguing that pre-namespace code is better. Only that it is better
understood because we have some experience with it. And maybe that it is not
worse, although I haven't seen all the code in the world.

>> >about _GetMin() and _GetMax(), or __GetMin() and __GetMax()?

That's still OK. The C standard does not disallow this or even discourage it
except through implication. All that is reserved are the names that the
compiler vendor puts in their headers with that format. It's about names,
not underscores. The C++ standard goes a little farther and says you can't
use those formats, but nothing bad happens if you do.

>Which raises the question: why not use _getMin() and _getMax()?  They
>start with a single underscore and do NOT have a capital letter.  Couldn't
>they be used safely?

As safely as any other name.


>BEGIN_MESSAGE_MAP is a macro that generates both some member
>function definitions and some data definitions.  And yet, at least IMHO,
>it still hasn't demonstrated why a macro is NEEDED.  (Perhaps if the
>macro call was hand-crafted you could convince me that it's less error
>prone, but it isn't, so it isn't.)  There may be more complex, contrived
>examples that don't shift into non-macro code so easily, but I think you'll
>have a tough time finding them, and I doubt they'll be real-world.

Think about the idiom, not the particular example I chose (although I
disagree that your example is as readable as the message map, what I am used
to notwithstanding). I won't have a tough time finding other examples
because I have used the idiom in several, non-contrived ways to map things
that would be unwieldy with non-macro C++ constructs, and they were quite
real-world.

>    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
>        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
>        // ...
>        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
>    };

I think if you tried to implement this, you'd find that there are a lot of
casts and other favors that the message map macros do for you especially
with the pointers to member functions. I think you would find that the array
initializers would be quite complex. I went through this a couple of times
mapping events to derived class functions in event-driven class libraries,
and it is a mess. Macros were the solution.

>With optimizations turned off?  Is that really fair?

Probably not. You asked for an example. I grabbed the closest one (all
that's installed here). I've seen the behavior in older compilers, but you
might be right; by now they might all do a proper job of inlining and
optimizing. But why should I trust the latest compiler? Why do I have to
look at disassemblies only to find out whether I could done it better (when
better in this sense matters) by using something with which I am
comfortable, which I fully understand, and that I know works? Perhaps holy
grails like type-safety and avoidance of side-effects are important for new
programmers or careless programmers or programmers who don't take time to
learn their tools, but #define is a tool, I know how it works, and I'll
continue to use it when I want it. (But I don't teach its use, so kick me.)

>they are never superior to other equivalent methods

That's a safe statement. How could anything be superior to its equal? :-)

> except for conditional compilation and compiler-defined constants.

And functions that compilers refuse to inline.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: zalman@netcom.com (Zalman Stern)
Date: 1998/06/25
Raw View
Al Stevens (alstevens@midifitz.com) wrote:
: Inline functions don't totally replace #define macros either. There is a
: cost in memory and processing time. Compare the underlying assembly code of
: the two idioms for a simple function with arguments. To preserve the
: "caller's" copy of the argument and avoid side effects, the C++ inline
: function pushes arguments on the stack and uses copies. The macro does not.

In general, you are wrong. For pass by reference, the above is untrue. For
arguments declared const (or infered to be unmodified by the astute
compiler) the above is untrue. For pass by value, you might have enough
registers to do the job or the passed in values might be dead after the
call in which case the compiler can reuse their locations.

Of course with the macro all of that is glossed over and you get semantics
which are unpredicatable from looking at the macro invocation alone. (And
which may be nothing like a function call. In fact, it may modify local
variables of the function that are not passed in to the macro, etc. )

: You'll never do away with the preprocessor. Even if you banished it from the
: language standard specifications, cpp is just a program that reads source
: code and emits source code. Programmers would continue to use it.

Yeah, but its a shame its such a lousy preprocessor with so little
knowledge of the language its processing. Templates for example blow the
doors off the preprocessor for a lot of things people used to use the
preprocessor for.

All in all Al, I wonder why you're bothering with C++. Why not just use C
or assembly and avoid the hassle of all the complexity? It really would
save you a lot of bitching too.

-Z-


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Daniel Parker" <danielp@nospam.com>
Date: 1998/06/25
Raw View
Al Stevens wrote in message ...
(AllanW is responsible for the >> bits)

>>Don't you dare point to MFC macros as a shining example of the way things
>>should work!
>
>>    BEGIN_MESSAGE_MAP(derived, base)
>>        ON_COMMAND_EX(ID_FILE_OPEN, OnFileOpen)
>>        // ...
>>    END_MESSAGE_MAP()
>>
>>we would have
>>
>>    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
>>        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
>>        // ...
>>        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
>>    };
>


>With all due respect, the former is, to this old eye, more readable and
less
>ugly.
>

I agree, with the one regret that in true Microsoft tradition, they did
absolutely nothing to protect their namespace when naming this macro.  Why
couldn't they have called it  MFC_BEGIN_MESSAGE_MAP?  As Valentin Bonnard
points out in a related post, past practice aside, there is no reason to
have name clashes with macros, and this is not a valid argument against
their use.

I frankly don't understand the horror that many developers reserve for
macros these days.  I hasten to add that I often need to follow Natham
Myer's excellent advice of

#ifdef min
#undefine min
#endif

and I've had to abandon using uppercase letters for enumeration constants
because of the pollution of the namespace by short macro names.  And I would
never use a macro in place of a function anymore, inlined or otherwise.  But
macros have very real value in wrapping short fragments of code.  Take the
implementation of a Singleton for example.  On a large project they could
number in the thousands.  There are different ways of implementing
Singletons, some more robust than others.  By wrapping the declaration and
implementation of a Singleton inside of DECLARE and IMPLEMENT macros, two
things are accomplished:  first, it is guaranteed that everybody is
implementing a Singleton in exactly the same way; and second, if a better
way is required, the change need only be done in one place, along with a
global recompile.

Regards,
Daniel Parker danielp@no_spam.anabasis.com



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/25
Raw View
>In general, you are wrong. For pass by reference, the above is untrue.

As it turns out, you are right. But it wasn't always so. See the other
messages on this subject.

>Yeah, but its a shame its such a lousy preprocessor with so little
>knowledge of the language its processing. Templates for example blow the
>doors off the preprocessor for a lot of things people used to use the
>preprocessor for.

Agreed.

>All in all Al, I wonder why you're bothering with C++. Why not just use C
>or assembly and avoid the hassle of all the complexity? It really would
>save you a lot of bitching too.


This thread is not about me and what I bother with; it is about macros and
inline functions, a small part of a much bigger language. I prefer to choose
my own tools and decide which parts of them I like and don't like. If you
disapprove of my opinions or my right to express them, don't click on the
posts with my name on them. I'll miss you, but I don't mind.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/06/25
Raw View
Al Stevens wrote:
...
> except through implication. All that is reserved are the names that the
> compiler vendor puts in their headers with that format. It's about names,
> not underscores. The C++ standard goes a little farther and says you can't
> use those formats, but nothing bad happens if you do.

The reserved identifier names can be classified as follows:
1. Publicly documented identifiers that users are intended to use.
2. Undocumented identifiers which should never occur in user code except
possibly as the result of the expansion of macros defined in standard
header files.
3. Identifiers not used by this implementation.

I would like to see an implementation that produced diagnostics for any
explicit use (in code that survives #if processing) of all identifiers
in the last two categories. I believe that such an implementation would
be conforming. In such an implementation, your statement that "nothing
bad happens" would be wrong.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/06/25
Raw View
In article <YG8k1.1034$u4.502233@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
>
> >CD2 2.10/2:
> >2 In addition, identifiers containing a double underscore (__) or
> >beginning with an underscore and an upper-case letter are reserved for
> >use by C++ implementations and standard libraries and shall not be
> >used otherwise; no diagnostic is required.
>
> There is such a thing as a compliant compiler. But a compliant program?
> What's the penalty for noncompliance if there is no diagnostic? I wish there
> was a diagnostic required. Compilers could be smart enough to suppress it
> when they are looking at declarations in their own headers.

There's an interesting thought.  But how would it work?

For compilers on systems with heirarchical directory structures, it could
give special treatment for headers in the compiler headers directory.  But
what stops you from moving your third-party header file into that directory?

The compiler could keep an internal list of header files.  So long as the
file was on this list, there would be no problem.  But what if I had my
own header file named "iostream.h" (remember -- there is no header file
with this name mentioned in the spec).  Would it detect this error there?
Also, the list of header files supplied with most compilers is starting to
get rather large, what with the standard C library, the C++ library, and
the STL.  The problem is even worse on most platforms, such as Windows,
that supply their own header files, and even worse than that when the vendor
supports extensions such as MFC or OWL...

Perhaps we want the intersection of those two ideas -- only for headers in
the compiler headers directory, and then only if it has a certain name.  I
suppose modifying the header files that comes with the compiler is a thought
too horrid to think of.  Besides, that couldn't happen by accident, and we
want to protect against accident and not fraud.  But if we wanted to, we
could take the CRC-16 of the entire header file.  Then only header files
that had the right name and the right CRC-16, and were in the right
directory, would supress the message. ...No, this is getting ugly.

It could use a #pragma, which was present in every compiler-supplied header
file.  Unlike most #pragmas I've used on purpose, this one would affect the
current file but not the rest of the translation unit.  (There is a precedent
for this in Microsoft, with the "#pragma once" for header files.)  Of course,
the user could put this #pragma in her own program, but again, that couldn't
happen by accident, so this one might work.

Come to think of it, Microsoft already has defined a pragma to disable any
warning, given it's message number.  So all they would have to do is to wrap
the header files like this:  #pragma warning(disable:9999)  // Header file
guts go here  #pragma warning(default:9999) Where 9999 would be replaced with
the new warning number.  (Currently Microsoft does not have a warning for use
of identifiers reserved for library headers.)

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/06/25
Raw View
Al Stevens wrote:
>
>
> >> >about _GetMin() and _GetMax(), or __GetMin() and __GetMax()?
>
> That's still OK. The C standard does not disallow this or even discourage it
> except through implication.

 All identifiers that begin with an underscore and either an
 uppercase letter or another underscore are always reserved for
 any use.

Sounds pretty clear to me: if you use such an identifier in your code
you do not have a conforming program.

> The C++ standard goes a little farther and says you can't
> use those formats, but nothing bad happens if you do.

If the implementor has used those names for library internals something
bad will definitely happen. That's why they're reserved: in order to
give implementors of the standard library room for identifiers that they
need. The fact that you can get away with it in many cases does not mean
that it is legal, and it does not mean that you will get away with it
when you use a different compiler.
 Don't mess around with identifiers like this. You're asking for
trouble.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/22
Raw View
>If you really mean to use the object directly, give the function
>a reference parameter or return value.  The resulting object code
>should be the same as with the macro.

Maybe, maybe not. It depends on some variable factors, such as the kind and
level of optimization you use (trust). For example, some compilers generate
quite different code for a macro than for a template or inline function when
you change optimizations. This is an implementation issue, and the standard
does not (and should not) mandate that inline code should do what macros do
under certain circumstances, such as using reference arguments.

>There are some limitations to inline functions. Typical compilers
>won't inline a function that contains a loop, goto, or switch.
>Some won't inline a function that is "too complicated".

Once again, an implementation issue. And there are time-critical programming
situtations where you need better control over what the compiler does, such
as in a realtime application. Macros, bless them, usually provide that
control.




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1998/06/23
Raw View
In article <6uvi1.20548$08.4852262@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
>
> >It's a pity that C++ doesn't provide an alternative to macros
> >for conditional compilation.  Not only do macros cause namespace
> >problems...
>
> Macros do not cause namespace problems. Namespaces introduced problems
> related to macros. Cpp is about 20 years old.

No, namespaces aggrevate the existing problem with macros.

Forget namespaces for a moment.  You're a third-party vendor selling tools
to perform higher mathematics, and you're creating a class that performs
statistical analysis.  You better not have a member named min or max --
those names are commonly used by macros.  If the user replaces those macros
with template functions, you'll probably be alright, but you can't assume
that the user isn't using some ancient C-language header file that was
included before yours.

By convention, macro names are USUALLY all capital; min and max are among a
huge list of frequent exceptions.  If you name your member functions
getMin() and getMax(), you're probably okay 99% of the time.  But not
100% -- it turns out that getMin() and getMax() are perfectly legal macro
names, even if they are unconventional.

What about _getMin() and _getMax(), or __getMin() and __getMax()?  The
Standard-C or Standard-C++ programmer isn't supposed to use names like this
for macros or any other identifier -- they're reserved for the compiler's
use only.  The catch is that you are also a programmer, under this
definition.  Since the compiler vendor probably didn't define these
particular names, they stand a good chance of working -- but it's still
non-standard.  Besides, how do you explain to your users that they have
to shove underscores in the middle of every member-function call they
make?  Let's face it,
    double average = ( statpackage._getMax() + statpackage._getMin() ) / 2.0;
is just too ugly for words.

Some people have had a lot of luck using names such as m_Xxx for all of their
data members.  Such names are unlikely to be macros, so chances are good that
this will solve half of your problem.  But the convention is used for DATA
members only -- you wouldn't expect to call a member function named m_GetMin.

There's one trick left.  Your header file can undefine each and every thing
that it's worried might be defined:
    #undef getMin
    #undef getMax
But this would be a huge list of symbols to undefine.  Worse, it wouldn't
really solve the problem -- either our library, or the original symbols,
would work correctly, but never both -- and which one worked would be
determined by which header file was defined LAST.

(However, I once knew a programmer trying to get at a protected class member.
Instead of fixing the problem, he simply added
   #define protected public
before he included that other header file.  Perhaps we could have solved this
with
    #undef protected
but we chose the better answer -- the programmer no longer works here.)

By this time, most class-library vendors just punt.  They avoid common macro
names, give their member functions reasonable names, and leave the remaining
burden on the programmer -- if they need this header file and also another
one that #defines a member name, then they must separate the code into two
sections, so that each can exist without the other header file.  This works,
but it isn't polite.

What we would like to do is guarantee that our header file doesn't break
any rules, and also that it always works, unless the programmer breaks the
rules or includes some other header file that breaks the rules.  We can't do
all of that right now.

> The argument against the preprocessor goes on. There are, however,
> constructions other than conditional compilation that #define does better.
> Win32 MFC and OWL message maps provide an example, and I have used that

Don't you dare point to MFC macros as a shining example of the way things
should work!  MFC and Windows header files are examples of expedience, not
elegance.  Each of them has many examples of elegance within them, but as
an overall pattern they are each horrendous in their own way.

As for the message-map #defines used in MFC, this problem could have been
solved completely without macros.  They could have defined the
AFX_MSGMAP_ENTRY structure to have several constructors, each of which
would have accepted a different function signature.  Then instead of

    BEGIN_MESSAGE_MAP(derived, base)
        ON_COMMAND_EX(ID_FILE_OPEN, OnFileOpen)
        // ...
    END_MESSAGE_MAP()

we would have

    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
        // ...
        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
    };

This wouldn't an exact replacement, because the mechanism for finding the
base class's message map would have to be changed, but the result would be
a lot cleaner and just as maintainable.  The only "drawbacks" are fewer
"behind-the-scenes" operations, a reduced dependance on the Application
Wizard, and code that's easier to understand and debug.  (Ever try to debug
an MFC program that doesn't deliver a message you think it should?  Whew!)

> technique to solve other similar mapping problems. In a user interface
> library, I used #define to implement dialog and menu resource scripts
> instead of using a separate resource compiler. Couldn't have done that
> without #define.

I bet you could have, if it had been a design goal.  You seem reasonably
intelligent.  There are always alternatives, although some of them are
unappealing at any given moment.

> Inline functions don't totally replace #define macros either. There is a
> cost in memory and processing time. Compare the underlying assembly code of
> the two idioms for a simple function with arguments. To preserve the
> "caller's" copy of the argument and avoid side effects, the C++ inline
> function pushes arguments on the stack and uses copies. The macro does not.

On what compiler is this always true?  A standards-conforming compiler would
do this when it's required, but not when it isn't.  After all, some inline
functions are supposed to alter the "caller's" copy of the argument, and
are supposed to propogate side effects.  Perhaps you need to brush up on your
use of references?
    void inline decrement(int &value) { --value; }
    // ...
        if (i>5) decrement(i);
Since this inline function uses a non-const reference, it is able to alter
the caller's "copy" of the int.  On my compiler the result is identical to
        if (i>5) --i;
If it isn't on yours, get an upgrade and/or complain loudly.

> You'll never do away with the preprocessor. Even if you banished it from the
> language standard specifications, cpp is just a program that reads source
> code and emits source code. Programmers would continue to use it.

Of course.  It isn't dead yet, any more than COBOL-68 is, and for the same
reasons.  Furthermore, I wouldn't want it to die.

However, I'm hoping that the NEXT revision to C++ will be to define
preprocessor values that are used ONLY for conditional compilation and
various constants.  For instance, by allowing preprocessor symbols to use
$ as an alphabetic character, and depricating the use of any preprocessor
symbol that doesn't start with $.  Symbols starting with TWO $ characters
would be reserved for the compiler/library vendors.  They could also define
some standard preprocessor symbols with compiler-defined values:

#ifndef $$RTTI
  #error Compiled without RTTI -- debugging info will not be complete
#elif $$VENDOR=="Microsoft"
  #include "MessageMap" // We have to live with this on MFC platforms
#else
  std::cout << $$FILE << " was compiled with " << $$VENDOR
      << " version " << $$VERSION << std::endl;
#endif

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/23
Raw View
>No, namespaces aggrevate the existing problem with macros.

Perhaps you should modify that to say, "...the perceived problem with
macros." Believe it or not, there are those of us who have no problem with
macros when properly used. That might be the consequence of long years of
experience with the idiom and its idiosyncrasies, experience that has
evolved into understanding, the kind of understanding that no one has with
some of the newer parts of C++. Any code idiom can be abused and no code
idiom can prevent its own abuse from abusing programmers.

>Forget namespaces for a moment.

Would that I could.

>...you can't assume
>that the user isn't using some ancient C-language header file that was
>included before yours.

A common problem that nothing new about namespaces or old about macros or
old or new about anything else is going to solve. The nice thing about old
header files and their old macros is that if they are really badly done, you
can change the header file macros without harming the library that was
compiled with them. (You can't do that with namespaces.) When dealing with
"ancient C-language header file[s]" you don't usually have to worry about
version control and product upgrades and retrofitting your corrections.
Mind, I don't preach that practice, but I have been known to practice it.

>What about _getMin() and _getMax(), or __getMin() and __getMax()?  The
>Standard-C or Standard-C++ programmer isn't supposed to use names like this
>for macros or any other identifier -- they're reserved for the compiler's
>use only.

That's a common misinterpretation of the C standard. The C standard doesn't
say that at all (unless it's tucked away in some obscure place not reachable
from the index or TOC). No where does the standard prohibit programmers from
using underscores as the first character of identifiers. It says that all
identifiers in standard library headers that begin with an underscore and
either a second underscore or an upper case letter are reserved identifiers
and that all identifers in standard library header files that begin with an
underscore and are in file scope are reserved identifers in that file scope.
It's about reserved identifiers, not reserved use of leading underscores.
But what those identifiers are is up to the compiler vendor. So a smart
programmer would interpret that and conclude that it is not a good idea to
use an underscore to begin an identifier because a future version of the
compiler library might reserve the same identifier. Thus evolved a
convention, but no such rule ever existed.

>Besides, how do you explain to your users that they have
>to shove underscores in the middle of every member-function call they
>make?

The same way you explain to them that they now have to use std::.

>is just too ugly for words.

....the eye of the beholder.

>   #define protected public

Yup, I've seen private done the same way. It made me think that name
mangling should be extended to include access specification to somehow
thwart such hacks. But I didn't think that for too long.

>Don't you dare point to MFC macros as a shining example of the way things
>should work!

I don't believe I did that, but I also don't believe that you get to tell me
what I dare not say. :-)

>    BEGIN_MESSAGE_MAP(derived, base)
>        ON_COMMAND_EX(ID_FILE_OPEN, OnFileOpen)
>        // ...
>    END_MESSAGE_MAP()
>
>we would have
>
>    const AFX_MSGMAP_ENTRY derived::messageMap[] = {
>        AFX_MSGMAP_ENTRY(ID_FILE_OPEN, OnFileOpen),
>        // ...
>        AFX_MSGMAP_ENTRY(AFX_MSGMAP_ENTRY::end_of_list)
>    };

With all due respect, the former is, to this old eye, more readable and less
ugly.

>I bet you could have, if it had been a design goal.

You'd lose your bet. I spent a lot of time on it.

>On what compiler is this always true?

VC++ 5.0 with optimizations turned off for one example. I posted about that
behavior in another response. It's an implementation issue, not a language
issue.

>Perhaps you need to brush up on your use of references?

Thanks. I'll go do that now. :-)
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/06/21
Raw View
"Al Stevens" <alstevens@midifitz.com> writes:

>Inline functions don't totally replace #define macros either. There is a
>cost in memory and processing time. Compare the underlying assembly code of
>the two idioms for a simple function with arguments. To preserve the
>"caller's" copy of the argument and avoid side effects, the C++ inline
>function pushes arguments on the stack and uses copies. The macro does not.

That is certainly not true in general. It might be true if you
are using an inappropriate version of an inline function.

For example, suppose your macro uses a class object directly.
If you write an inline function that takes the object as a
value parameter or returns it by value, you will get less efficient
code. But the function also does not have the same semantics as
the macro. (The input-output semantics of a function are explicit;
those of a macro are implicit.)

If you really mean to use the object directly, give the function
a reference parameter or return value.  The resulting object code
should be the same as with the macro.

But if you didn't really mean to use the object directly,
the macro was a bug waiting to happen.

There are some limitations to inline functions. Typical compilers
won't inline a function that contains a loop, goto, or switch.
Some won't inline a function that is "too complicated". In
such cases, you might get less efficient code with the inline
function. But before I worried about the putative loss of effiency,
I'd consider the maintainance aspects of such complicated macros,
and find by measurement whether the less efficient code in fact
affected program performance.

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 1998/06/19
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

>As for macros in third-party libraries, I hope they are used
>only for configuration control, and that they are long and
>ugly with the vendor's name as a prefix.

It's a pity that C++ doesn't provide an alternative to macros
for conditional compilation.  Not only do macros cause namespace
problems, using them for conditional compilation is also error-prone:
if you misspell a macro name in a `#ifdef', then you won't get any
warning from the compiler, and unfortunately the same generally
applies even if you use `#if' instead of `#ifdef'.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1998/06/19
Raw View
>It's a pity that C++ doesn't provide an alternative to macros
>for conditional compilation.  Not only do macros cause namespace
>problems...

Macros do not cause namespace problems. Namespaces introduced problems
related to macros. Cpp is about 20 years old.

The argument against the preprocessor goes on. There are, however,
constructions other than conditional compilation that #define does better.
Win32 MFC and OWL message maps provide an example, and I have used that
technique to solve other similar mapping problems. In a user interface
library, I used #define to implement dialog and menu resource scripts
instead of using a separate resource compiler. Couldn't have done that
without #define.

Inline functions don't totally replace #define macros either. There is a
cost in memory and processing time. Compare the underlying assembly code of
the two idioms for a simple function with arguments. To preserve the
"caller's" copy of the argument and avoid side effects, the C++ inline
function pushes arguments on the stack and uses copies. The macro does not.

You'll never do away with the preprocessor. Even if you banished it from the
language standard specifications, cpp is just a program that reads source
code and emits source code. Programmers would continue to use it.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Mike Davies <mike_davies@noco.demon.co.uk>
Date: 1998/06/20
Raw View
In article <6uvi1.20548$08.4852262@newscene.newscene.com>, Al Stevens
<alstevens@midifitz.com> writes
>
>Inline functions don't totally replace #define macros either. There is a
>cost in memory and processing time. Compare the underlying assembly code of
>the two idioms for a simple function with arguments. To preserve the
>"caller's" copy of the argument and avoid side effects, the C++ inline
>function pushes arguments on the stack and uses copies. The macro does not.

I think you can use references as arguments to avoid this.

--
Mike Davies
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]